js/src/jit/arm/Simulator-arm.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     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.
    29 #include "jit/arm/Simulator-arm.h"
    31 #include "mozilla/Casting.h"
    32 #include "mozilla/FloatingPoint.h"
    33 #include "mozilla/Likely.h"
    34 #include "mozilla/MathAlgorithms.h"
    36 #include "jit/arm/Assembler-arm.h"
    37 #include "jit/AsmJS.h"
    38 #include "vm/Runtime.h"
    40 extern "C" {
    42 int64_t
    43 __aeabi_idivmod(int x, int y)
    44 {
    45     uint32_t lo = uint32_t(x / y);
    46     uint32_t hi = uint32_t(x % y);
    47     return (int64_t(hi) << 32) | lo;
    48 }
    50 int64_t
    51 __aeabi_uidivmod(int x, int y)
    52 {
    53     uint32_t lo = uint32_t(x) / uint32_t(y);
    54     uint32_t hi = uint32_t(x) % uint32_t(y);
    55     return (int64_t(hi) << 32) | lo;
    56 }
    57 }
    59 namespace js {
    60 namespace jit {
    62 // Load/store multiple addressing mode.
    63 enum BlockAddrMode {
    64     // Alias modes for comparison when writeback does not matter.
    65     da_x         = (0|0|0) << 21,  // Decrement after.
    66     ia_x         = (0|4|0) << 21,  // Increment after.
    67     db_x         = (8|0|0) << 21,  // Decrement before.
    68     ib_x         = (8|4|0) << 21,  // Increment before.
    69 };
    71 // Type of VFP register. Determines register encoding.
    72 enum VFPRegPrecision {
    73     kSinglePrecision = 0,
    74     kDoublePrecision = 1
    75 };
    77 enum NeonListType {
    78     nlt_1 = 0x7,
    79     nlt_2 = 0xA,
    80     nlt_3 = 0x6,
    81     nlt_4 = 0x2
    82 };
    84 // Supervisor Call (svc) specific support.
    86 // Special Software Interrupt codes when used in the presence of the ARM
    87 // simulator.
    88 // svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
    89 // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
    90 enum SoftwareInterruptCodes {
    91     kCallRtRedirected = 0x10,  // Transition to C code.
    92     kBreakpoint= 0x20, // Breakpoint.
    93     kStopCode = 1 << 23 // Stop.
    94 };
    96 const uint32_t kStopCodeMask = kStopCode - 1;
    97 const uint32_t kMaxStopCode = kStopCode - 1;
    99 // -----------------------------------------------------------------------------
   100 // Instruction abstraction.
   102 // The class Instruction enables access to individual fields defined in the ARM
   103 // architecture instruction set encoding as described in figure A3-1.
   104 // Note that the Assembler uses typedef int32_t Instr.
   105 //
   106 // Example: Test whether the instruction at ptr does set the condition code
   107 // bits.
   108 //
   109 // bool InstructionSetsConditionCodes(byte* ptr) {
   110 //   Instruction* instr = Instruction::At(ptr);
   111 //   int type = instr->TypeValue();
   112 //   return ((type == 0) || (type == 1)) && instr->hasS();
   113 // }
   114 //
   115 class SimInstruction {
   116   public:
   117     enum {
   118         kInstrSize = 4,
   119         kPCReadOffset = 8
   120     };
   122     // Get the raw instruction bits.
   123     inline Instr instructionBits() const {
   124         return *reinterpret_cast<const Instr*>(this);
   125     }
   127     // Set the raw instruction bits to value.
   128     inline void setInstructionBits(Instr value) {
   129         *reinterpret_cast<Instr*>(this) = value;
   130     }
   132     // Read one particular bit out of the instruction bits.
   133     inline int bit(int nr) const {
   134         return (instructionBits() >> nr) & 1;
   135     }
   137     // Read a bit field's value out of the instruction bits.
   138     inline int bits(int hi, int lo) const {
   139         return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
   140     }
   142     // Read a bit field out of the instruction bits.
   143     inline int bitField(int hi, int lo) const {
   144         return instructionBits() & (((2 << (hi - lo)) - 1) << lo);
   145     }
   147     // Accessors for the different named fields used in the ARM encoding.
   148     // The naming of these accessor corresponds to figure A3-1.
   149     //
   150     // Two kind of accessors are declared:
   151     // - <Name>Field() will return the raw field, i.e. the field's bits at their
   152     //   original place in the instruction encoding.
   153     //   e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
   154     //   0xC0810002 conditionField(instr) will return 0xC0000000.
   155     // - <Name>Value() will return the field value, shifted back to bit 0.
   156     //   e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
   157     //   0xC0810002 conditionField(instr) will return 0xC.
   159     // Generally applicable fields
   160     inline Assembler::ARMCondition conditionField() const {
   161         return static_cast<Assembler::ARMCondition>(bitField(31, 28));
   162     }
   163     inline int typeValue() const { return bits(27, 25); }
   164     inline int specialValue() const { return bits(27, 23); }
   166     inline int rnValue() const { return bits(19, 16); }
   167     inline int rdValue() const { return bits(15, 12); }
   169     inline int coprocessorValue() const { return bits(11, 8); }
   171     // Support for VFP.
   172     // Vn(19-16) | Vd(15-12) |  Vm(3-0)
   173     inline int vnValue() const { return bits(19, 16); }
   174     inline int vmValue() const { return bits(3, 0); }
   175     inline int vdValue() const { return bits(15, 12); }
   176     inline int nValue() const { return bit(7); }
   177     inline int mValue() const { return bit(5); }
   178     inline int dValue() const { return bit(22); }
   179     inline int rtValue() const { return bits(15, 12); }
   180     inline int pValue() const { return bit(24); }
   181     inline int uValue() const { return bit(23); }
   182     inline int opc1Value() const { return (bit(23) << 2) | bits(21, 20); }
   183     inline int opc2Value() const { return bits(19, 16); }
   184     inline int opc3Value() const { return bits(7, 6); }
   185     inline int szValue() const { return bit(8); }
   186     inline int VLValue() const { return bit(20); }
   187     inline int VCValue() const { return bit(8); }
   188     inline int VAValue() const { return bits(23, 21); }
   189     inline int VBValue() const { return bits(6, 5); }
   190     inline int VFPNRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 16, 7); }
   191     inline int VFPMRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 0, 5); }
   192     inline int VFPDRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 12, 22); }
   194     // Fields used in Data processing instructions
   195     inline int opcodeValue() const { return static_cast<ALUOp>(bits(24, 21)); }
   196     inline ALUOp opcodeField() const { return static_cast<ALUOp>(bitField(24, 21)); }
   197     inline int sValue() const { return bit(20); }
   199     // with register
   200     inline int rmValue() const { return bits(3, 0); }
   201     inline ShiftType shifttypeValue() const { return static_cast<ShiftType>(bits(6, 5)); }
   202     inline int rsValue() const { return bits(11, 8); }
   203     inline int shiftAmountValue() const { return bits(11, 7); }
   205     // with immediate
   206     inline int rotateValue() const { return bits(11, 8); }
   207     inline int immed8Value() const { return bits(7, 0); }
   208     inline int immed4Value() const { return bits(19, 16); }
   209     inline int immedMovwMovtValue() const { return immed4Value() << 12 | offset12Value(); }
   211     // Fields used in Load/Store instructions
   212     inline int PUValue() const { return bits(24, 23); }
   213     inline int PUField() const { return bitField(24, 23); }
   214     inline int bValue() const { return bit(22); }
   215     inline int wValue() const { return bit(21); }
   216     inline int lValue() const { return bit(20); }
   218     // with register uses same fields as Data processing instructions above
   219     // with immediate
   220     inline int offset12Value() const { return bits(11, 0); }
   222     // multiple
   223     inline int rlistValue() const { return bits(15, 0); }
   225     // extra loads and stores
   226     inline int signValue() const { return bit(6); }
   227     inline int hValue() const { return bit(5); }
   228     inline int immedHValue() const { return bits(11, 8); }
   229     inline int immedLValue() const { return bits(3, 0); }
   231     // Fields used in Branch instructions
   232     inline int linkValue() const { return bit(24); }
   233     inline int sImmed24Value() const { return ((instructionBits() << 8) >> 8); }
   235     // Fields used in Software interrupt instructions
   236     inline SoftwareInterruptCodes svcValue() const {
   237         return static_cast<SoftwareInterruptCodes>(bits(23, 0));
   238     }
   240     // Test for special encodings of type 0 instructions (extra loads and stores,
   241     // as well as multiplications).
   242     inline bool isSpecialType0() const { return (bit(7) == 1) && (bit(4) == 1); }
   244     // Test for miscellaneous instructions encodings of type 0 instructions.
   245     inline bool isMiscType0() const {
   246         return bit(24) == 1 && bit(23) == 0 && bit(20) == 0 && (bit(7) == 0);
   247     }
   249     // Test for a nop instruction, which falls under type 1.
   250     inline bool isNopType1() const { return bits(24, 0) == 0x0120F000; }
   252     // Test for a stop instruction.
   253     inline bool isStop() const {
   254         return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode;
   255     }
   257     // Special accessors that test for existence of a value.
   258     inline bool hasS()    const { return sValue() == 1; }
   259     inline bool hasB()    const { return bValue() == 1; }
   260     inline bool hasW()    const { return wValue() == 1; }
   261     inline bool hasL()    const { return lValue() == 1; }
   262     inline bool hasU()    const { return uValue() == 1; }
   263     inline bool hasSign() const { return signValue() == 1; }
   264     inline bool hasH()    const { return hValue() == 1; }
   265     inline bool hasLink() const { return linkValue() == 1; }
   267     // Decoding the double immediate in the vmov instruction.
   268     double doubleImmedVmov() const;
   269     // Decoding the float32 immediate in the vmov.f32 instruction.
   270     float float32ImmedVmov() const;
   272   private:
   273     // Join split register codes, depending on single or double precision.
   274     // four_bit is the position of the least-significant bit of the four
   275     // bit specifier. one_bit is the position of the additional single bit
   276     // specifier.
   277     inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) {
   278         if (pre == kSinglePrecision)
   279             return (bits(four_bit + 3, four_bit) << 1) | bit(one_bit);
   280         return (bit(one_bit) << 4) | bits(four_bit + 3, four_bit);
   281     }
   283     SimInstruction() MOZ_DELETE;
   284     SimInstruction(const SimInstruction &other) MOZ_DELETE;
   285     void operator=(const SimInstruction &other) MOZ_DELETE;
   286 };
   288 double
   289 SimInstruction::doubleImmedVmov() const
   290 {
   291     // Reconstruct a double from the immediate encoded in the vmov instruction.
   292     //
   293     //   instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
   294     //   double: [aBbbbbbb,bbcdefgh,00000000,00000000,
   295     //            00000000,00000000,00000000,00000000]
   296     //
   297     // where B = ~b. Only the high 16 bits are affected.
   298     uint64_t high16;
   299     high16  = (bits(17, 16) << 4) | bits(3, 0);   // xxxxxxxx,xxcdefgh.
   300     high16 |= (0xff * bit(18)) << 6;              // xxbbbbbb,bbxxxxxx.
   301     high16 |= (bit(18) ^ 1) << 14;                // xBxxxxxx,xxxxxxxx.
   302     high16 |= bit(19) << 15;                      // axxxxxxx,xxxxxxxx.
   304     uint64_t imm = high16 << 48;
   305     return mozilla::BitwiseCast<double>(imm);
   306 }
   308 float
   309 SimInstruction::float32ImmedVmov() const
   310 {
   311     // Reconstruct a float32 from the immediate encoded in the vmov instruction.
   312     //
   313     //   instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
   314     //   float32: [aBbbbbbc, defgh000, 00000000, 00000000]
   315     //
   316     // where B = ~b. Only the high 16 bits are affected.
   317     uint32_t imm;
   318     imm  = (bits(17, 16) << 23) | (bits(3, 0) << 19); // xxxxxxxc,defgh000.0.0
   319     imm |= (0x1f * bit(18)) << 25;                    // xxbbbbbx,xxxxxxxx.0.0
   320     imm |= (bit(18) ^ 1) << 30;                       // xBxxxxxx,xxxxxxxx.0.0
   321     imm |= bit(19) << 31;                             // axxxxxxx,xxxxxxxx.0.0
   323     return mozilla::BitwiseCast<float>(imm);
   324 }
   326 class CachePage
   327 {
   328   public:
   329     static const int LINE_VALID = 0;
   330     static const int LINE_INVALID = 1;
   331     static const int kPageShift = 12;
   332     static const int kPageSize = 1 << kPageShift;
   333     static const int kPageMask = kPageSize - 1;
   334     static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
   335     static const int kLineLength = 1 << kLineShift;
   336     static const int kLineMask = kLineLength - 1;
   338     CachePage() {
   339         memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
   340     }
   341     char *validityByte(int offset) {
   342         return &validity_map_[offset >> kLineShift];
   343     }
   344     char *cachedData(int offset) {
   345         return &data_[offset];
   346     }
   348   private:
   349     char data_[kPageSize];   // The cached data.
   350     static const int kValidityMapSize = kPageSize >> kLineShift;
   351     char validity_map_[kValidityMapSize];  // One byte per line.
   352 };
   354 class Redirection;
   356 class SimulatorRuntime
   357 {
   358     friend class AutoLockSimulatorRuntime;
   360     Redirection *redirection_;
   362     // ICache checking.
   363     struct ICacheHasher {
   364         typedef void *Key;
   365         typedef void *Lookup;
   366         static HashNumber hash(const Lookup &l);
   367         static bool match(const Key &k, const Lookup &l);
   368     };
   370   public:
   371     typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
   373   protected:
   374     ICacheMap icache_;
   376     // Synchronize access between main thread and compilation/PJS threads.
   377     PRLock *lock_;
   378     mozilla::DebugOnly<PRThread *> lockOwner_;
   380   public:
   381     SimulatorRuntime()
   382       : redirection_(nullptr),
   383         lock_(nullptr),
   384         lockOwner_(nullptr)
   385     {}
   386     ~SimulatorRuntime();
   387     bool init() {
   388 #ifdef JS_THREADSAFE
   389         lock_ = PR_NewLock();
   390         if (!lock_)
   391             return false;
   392 #endif
   393         if (!icache_.init())
   394             return false;
   395         return true;
   396     }
   397     ICacheMap &icache() {
   398 #ifdef JS_THREADSAFE
   399         MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
   400 #endif
   401         return icache_;
   402     }
   403     Redirection *redirection() const {
   404 #ifdef JS_THREADSAFE
   405         MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
   406 #endif
   407         return redirection_;
   408     }
   409     void setRedirection(js::jit::Redirection *redirection) {
   410 #ifdef JS_THREADSAFE
   411         MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
   412 #endif
   413         redirection_ = redirection;
   414     }
   415 };
   417 class AutoLockSimulatorRuntime
   418 {
   419   protected:
   420     SimulatorRuntime *srt_;
   422   public:
   423     AutoLockSimulatorRuntime(SimulatorRuntime *srt)
   424       : srt_(srt)
   425     {
   426 #ifdef JS_THREADSAFE
   427         PR_Lock(srt_->lock_);
   428         MOZ_ASSERT(!srt_->lockOwner_);
   429 #ifdef DEBUG
   430         srt_->lockOwner_ = PR_GetCurrentThread();
   431 #endif
   432 #endif
   433     }
   435     ~AutoLockSimulatorRuntime() {
   436 #ifdef JS_THREADSAFE
   437         MOZ_ASSERT(srt_->lockOwner_ == PR_GetCurrentThread());
   438         srt_->lockOwner_ = nullptr;
   439         PR_Unlock(srt_->lock_);
   440 #endif
   441     }
   442 };
   444 bool Simulator::ICacheCheckingEnabled = false;
   446 int64_t Simulator::StopSimAt = -1L;
   448 SimulatorRuntime *
   449 CreateSimulatorRuntime()
   450 {
   451     SimulatorRuntime *srt = js_new<SimulatorRuntime>();
   452     if (!srt)
   453         return nullptr;
   455     if (!srt->init()) {
   456         js_delete(srt);
   457         return nullptr;
   458     }
   460     if (getenv("ARM_SIM_ICACHE_CHECKS"))
   461         Simulator::ICacheCheckingEnabled = true;
   463     char *stopAtStr = getenv("ARM_SIM_STOP_AT");
   464     int64_t stopAt;
   465     if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
   466         fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
   467         Simulator::StopSimAt = stopAt;
   468     }
   470     return srt;
   471 }
   473 void
   474 DestroySimulatorRuntime(SimulatorRuntime *srt)
   475 {
   476     js_delete(srt);
   477 }
   479 // The ArmDebugger class is used by the simulator while debugging simulated ARM
   480 // code.
   481 class ArmDebugger {
   482   public:
   483     explicit ArmDebugger(Simulator *sim) : sim_(sim) { }
   485     void stop(SimInstruction *instr);
   486     void debug();
   488   private:
   489     static const Instr kBreakpointInstr = (Assembler::AL | (7 * (1 << 25)) | (1* (1 << 24)) | kBreakpoint);
   490     static const Instr kNopInstr = (Assembler::AL | (13 * (1 << 21)));
   492     Simulator* sim_;
   494     int32_t getRegisterValue(int regnum);
   495     double getRegisterPairDoubleValue(int regnum);
   496     double getVFPDoubleRegisterValue(int regnum);
   497     bool getValue(const char *desc, int32_t *value);
   498     bool getVFPDoubleValue(const char *desc, double *value);
   500     // Set or delete a breakpoint. Returns true if successful.
   501     bool setBreakpoint(SimInstruction *breakpc);
   502     bool deleteBreakpoint(SimInstruction *breakpc);
   504     // Undo and redo all breakpoints. This is needed to bracket disassembly and
   505     // execution to skip past breakpoints when run from the debugger.
   506     void undoBreakpoints();
   507     void redoBreakpoints();
   508 };
   510 void
   511 ArmDebugger::stop(SimInstruction * instr)
   512 {
   513     // Get the stop code.
   514     uint32_t code = instr->svcValue() & kStopCodeMask;
   515     // Retrieve the encoded address, which comes just after this stop.
   516     char* msg = *reinterpret_cast<char**>(sim_->get_pc()
   517                                           + SimInstruction::kInstrSize);
   518     // Update this stop description.
   519     if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
   520         sim_->watched_stops_[code].desc = msg;
   521     }
   522     // Print the stop message and code if it is not the default code.
   523     if (code != kMaxStopCode) {
   524         printf("Simulator hit stop %u: %s\n", code, msg);
   525     } else {
   526         printf("Simulator hit %s\n", msg);
   527     }
   528     sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
   529     debug();
   530 }
   532 int32_t
   533 ArmDebugger::getRegisterValue(int regnum)
   534 {
   535     if (regnum == Registers::pc)
   536         return sim_->get_pc();
   537     return sim_->get_register(regnum);
   538 }
   540 double
   541 ArmDebugger::getRegisterPairDoubleValue(int regnum)
   542 {
   543     return sim_->get_double_from_register_pair(regnum);
   544 }
   546 double
   547 ArmDebugger::getVFPDoubleRegisterValue(int regnum)
   548 {
   549     return sim_->get_double_from_d_register(regnum);
   550 }
   552 bool
   553 ArmDebugger::getValue(const char *desc, int32_t *value)
   554 {
   555     Register reg = Register::FromName(desc);
   556     if (reg != InvalidReg) {
   557         *value = getRegisterValue(reg.code());
   558         return true;
   559     }
   560     if (strncmp(desc, "0x", 2) == 0)
   561         return sscanf(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
   562     return sscanf(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
   563 }
   565 bool
   566 ArmDebugger::getVFPDoubleValue(const char *desc, double *value)
   567 {
   568     FloatRegister reg = FloatRegister::FromName(desc);
   569     if (reg != InvalidFloatReg) {
   570         *value = sim_->get_double_from_d_register(reg.code());
   571         return true;
   572     }
   573     return false;
   574 }
   576 bool
   577 ArmDebugger::setBreakpoint(SimInstruction *breakpc)
   578 {
   579     // Check if a breakpoint can be set. If not return without any side-effects.
   580     if (sim_->break_pc_)
   581         return false;
   583     // Set the breakpoint.
   584     sim_->break_pc_ = breakpc;
   585     sim_->break_instr_ = breakpc->instructionBits();
   586     // Not setting the breakpoint instruction in the code itself. It will be set
   587     // when the debugger shell continues.
   588     return true;
   589 }
   591 bool
   592 ArmDebugger::deleteBreakpoint(SimInstruction *breakpc)
   593 {
   594     if (sim_->break_pc_ != nullptr)
   595         sim_->break_pc_->setInstructionBits(sim_->break_instr_);
   597     sim_->break_pc_ = nullptr;
   598     sim_->break_instr_ = 0;
   599     return true;
   600 }
   602 void
   603 ArmDebugger::undoBreakpoints()
   604 {
   605     if (sim_->break_pc_)
   606         sim_->break_pc_->setInstructionBits(sim_->break_instr_);
   607 }
   609 void
   610 ArmDebugger::redoBreakpoints()
   611 {
   612     if (sim_->break_pc_)
   613         sim_->break_pc_->setInstructionBits(kBreakpointInstr);
   614 }
   616 static char *
   617 ReadLine(const char *prompt)
   618 {
   619     char *result = nullptr;
   620     char line_buf[256];
   621     int offset = 0;
   622     bool keep_going = true;
   623     fprintf(stdout, "%s", prompt);
   624     fflush(stdout);
   625     while (keep_going) {
   626         if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
   627             // fgets got an error. Just give up.
   628             if (result)
   629                 js_delete(result);
   630             return nullptr;
   631         }
   632         int len = strlen(line_buf);
   633         if (len > 0 && line_buf[len - 1] == '\n') {
   634             // Since we read a new line we are done reading the line. This
   635             // will exit the loop after copying this buffer into the result.
   636             keep_going = false;
   637         }
   638         if (!result) {
   639             // Allocate the initial result and make room for the terminating '\0'
   640             result = (char *)js_malloc(len + 1);
   641             if (!result)
   642                 return nullptr;
   643         } else {
   644             // Allocate a new result with enough room for the new addition.
   645             int new_len = offset + len + 1;
   646             char *new_result = (char *)js_malloc(new_len);
   647             if (!new_result)
   648                 return nullptr;
   649             // Copy the existing input into the new array and set the new
   650             // array as the result.
   651             memcpy(new_result, result, offset * sizeof(char));
   652             js_free(result);
   653             result = new_result;
   654         }
   655         // Copy the newly read line into the result.
   656         memcpy(result + offset, line_buf, len * sizeof(char));
   657         offset += len;
   658     }
   660     MOZ_ASSERT(result);
   661     result[offset] = '\0';
   662     return result;
   663 }
   665 static void
   666 DisassembleInstruction(uint32_t pc)
   667 {
   668     uint8_t *bytes = reinterpret_cast<uint8_t *>(pc);
   669     char hexbytes[256];
   670     sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3]);
   671     char llvmcmd[1024];
   672     sprintf(llvmcmd, "bash -c \"echo -n '%p'; echo '%s' | "
   673             "llvm-mc -disassemble -arch=arm -mcpu=cortex-a9 | "
   674             "grep -v pure_instructions | grep -v .text\"",
   675             reinterpret_cast<void*>(pc), hexbytes);
   676     system(llvmcmd);
   677 }
   679 void
   680 ArmDebugger::debug()
   681 {
   682     intptr_t last_pc = -1;
   683     bool done = false;
   685 #define COMMAND_SIZE 63
   686 #define ARG_SIZE 255
   688 #define STR(a) #a
   689 #define XSTR(a) STR(a)
   691     char cmd[COMMAND_SIZE + 1];
   692     char arg1[ARG_SIZE + 1];
   693     char arg2[ARG_SIZE + 1];
   694     char *argv[3] = { cmd, arg1, arg2 };
   696     // make sure to have a proper terminating character if reaching the limit
   697     cmd[COMMAND_SIZE] = 0;
   698     arg1[ARG_SIZE] = 0;
   699     arg2[ARG_SIZE] = 0;
   701     // Undo all set breakpoints while running in the debugger shell. This will
   702     // make them invisible to all commands.
   703     undoBreakpoints();
   705     while (!done && !sim_->has_bad_pc()) {
   706         if (last_pc != sim_->get_pc()) {
   707             DisassembleInstruction(sim_->get_pc());
   708             last_pc = sim_->get_pc();
   709         }
   710         char *line = ReadLine("sim> ");
   711         if (line == nullptr) {
   712             break;
   713         } else {
   714             char *last_input = sim_->lastDebuggerInput();
   715             if (strcmp(line, "\n") == 0 && last_input != nullptr) {
   716                 line = last_input;
   717             } else {
   718                 // Ownership is transferred to sim_;
   719                 sim_->setLastDebuggerInput(line);
   720             }
   722             // Use sscanf to parse the individual parts of the command line. At the
   723             // moment no command expects more than two parameters.
   724             int argc = sscanf(line,
   725                               "%" XSTR(COMMAND_SIZE) "s "
   726                               "%" XSTR(ARG_SIZE) "s "
   727                               "%" XSTR(ARG_SIZE) "s",
   728                               cmd, arg1, arg2);
   729             if (argc < 0) {
   730                 continue;
   731             } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
   732                 sim_->instructionDecode(reinterpret_cast<SimInstruction *>(sim_->get_pc()));
   733                 sim_->icount_++;
   734             } else if ((strcmp(cmd, "skip") == 0)) {
   735                 sim_->set_pc(sim_->get_pc() + 4);
   736                 sim_->icount_++;
   737             } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
   738                 // Execute the one instruction we broke at with breakpoints disabled.
   739                 sim_->instructionDecode(reinterpret_cast<SimInstruction *>(sim_->get_pc()));
   740                 sim_->icount_++;
   741                 // Leave the debugger shell.
   742                 done = true;
   743             } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
   744                 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
   745                     int32_t value;
   746                     double dvalue;
   747                     if (strcmp(arg1, "all") == 0) {
   748                         for (uint32_t i = 0; i < Registers::Total; i++) {
   749                             value = getRegisterValue(i);
   750                             printf("%3s: 0x%08x %10d", Registers::GetName(i), value, value);
   751                             if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
   752                                 i < 8 &&
   753                                 (i % 2) == 0) {
   754                                 dvalue = getRegisterPairDoubleValue(i);
   755                                 printf(" (%f)\n", dvalue);
   756                             } else {
   757                                 printf("\n");
   758                             }
   759                         }
   760                         for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
   761                             dvalue = getVFPDoubleRegisterValue(i);
   762                             uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
   763                             printf("%3s: %f 0x%08x %08x\n",
   764                                    FloatRegister::FromCode(i).name(),
   765                                    dvalue,
   766                                    static_cast<uint32_t>(as_words >> 32),
   767                                    static_cast<uint32_t>(as_words & 0xffffffff));
   768                         }
   769                     } else {
   770                         if (getValue(arg1, &value)) {
   771                             printf("%s: 0x%08x %d \n", arg1, value, value);
   772                         } else if (getVFPDoubleValue(arg1, &dvalue)) {
   773                             uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
   774                             printf("%s: %f 0x%08x %08x\n",
   775                                    arg1,
   776                                    dvalue,
   777                                    static_cast<uint32_t>(as_words >> 32),
   778                                    static_cast<uint32_t>(as_words & 0xffffffff));
   779                         } else {
   780                             printf("%s unrecognized\n", arg1);
   781                         }
   782                     }
   783                 } else {
   784                     printf("print <register>\n");
   785                 }
   786             } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
   787                 int32_t *cur = nullptr;
   788                 int32_t *end = nullptr;
   789                 int next_arg = 1;
   791                 if (strcmp(cmd, "stack") == 0) {
   792                     cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
   793                 } else {  // "mem"
   794                     int32_t value;
   795                     if (!getValue(arg1, &value)) {
   796                         printf("%s unrecognized\n", arg1);
   797                         continue;
   798                     }
   799                     cur = reinterpret_cast<int32_t*>(value);
   800                     next_arg++;
   801                 }
   803                 int32_t words;
   804                 if (argc == next_arg) {
   805                     words = 10;
   806                 } else {
   807                     if (!getValue(argv[next_arg], &words)) {
   808                         words = 10;
   809                     }
   810                 }
   811                 end = cur + words;
   813                 while (cur < end) {
   814                     printf("  %p:  0x%08x %10d", cur, *cur, *cur);
   815                     printf("\n");
   816                     cur++;
   817                 }
   818             } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
   819                 uint8_t *cur = nullptr;
   820                 uint8_t *end = nullptr;
   821                 if (argc == 1) {
   822                     cur = reinterpret_cast<uint8_t *>(sim_->get_pc());
   823                     end = cur + (10 * SimInstruction::kInstrSize);
   824                 } else if (argc == 2) {
   825                     Register reg = Register::FromName(arg1);
   826                     if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
   827                         // The argument is an address or a register name.
   828                         int32_t value;
   829                         if (getValue(arg1, &value)) {
   830                             cur = reinterpret_cast<uint8_t *>(value);
   831                             // Disassemble 10 instructions at <arg1>.
   832                             end = cur + (10 * SimInstruction::kInstrSize);
   833                         }
   834                     } else {
   835                         // The argument is the number of instructions.
   836                         int32_t value;
   837                         if (getValue(arg1, &value)) {
   838                             cur = reinterpret_cast<uint8_t *>(sim_->get_pc());
   839                             // Disassemble <arg1> instructions.
   840                             end = cur + (value * SimInstruction::kInstrSize);
   841                         }
   842                     }
   843                 } else {
   844                     int32_t value1;
   845                     int32_t value2;
   846                     if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
   847                         cur = reinterpret_cast<uint8_t *>(value1);
   848                         end = cur + (value2 * SimInstruction::kInstrSize);
   849                     }
   850                 }
   851                 while (cur < end) {
   852                     DisassembleInstruction(uint32_t(cur));
   853                     cur += SimInstruction::kInstrSize;
   854                 }
   855             } else if (strcmp(cmd, "gdb") == 0) {
   856                 printf("relinquishing control to gdb\n");
   857                 asm("int $3");
   858                 printf("regaining control from gdb\n");
   859             } else if (strcmp(cmd, "break") == 0) {
   860                 if (argc == 2) {
   861                     int32_t value;
   862                     if (getValue(arg1, &value)) {
   863                         if (!setBreakpoint(reinterpret_cast<SimInstruction *>(value)))
   864                             printf("setting breakpoint failed\n");
   865                     } else {
   866                         printf("%s unrecognized\n", arg1);
   867                     }
   868                 } else {
   869                     printf("break <address>\n");
   870                 }
   871             } else if (strcmp(cmd, "del") == 0) {
   872                 if (!deleteBreakpoint(nullptr)) {
   873                     printf("deleting breakpoint failed\n");
   874                 }
   875             } else if (strcmp(cmd, "flags") == 0) {
   876                 printf("N flag: %d; ", sim_->n_flag_);
   877                 printf("Z flag: %d; ", sim_->z_flag_);
   878                 printf("C flag: %d; ", sim_->c_flag_);
   879                 printf("V flag: %d\n", sim_->v_flag_);
   880                 printf("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
   881                 printf("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
   882                 printf("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
   883                 printf("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
   884                 printf("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
   885             } else if (strcmp(cmd, "stop") == 0) {
   886                 int32_t value;
   887                 intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
   888                 SimInstruction *stop_instr = reinterpret_cast<SimInstruction *>(stop_pc);
   889                 SimInstruction *msg_address =
   890                     reinterpret_cast<SimInstruction *>(stop_pc + SimInstruction::kInstrSize);
   891                 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
   892                     // Remove the current stop.
   893                     if (sim_->isStopInstruction(stop_instr)) {
   894                         stop_instr->setInstructionBits(kNopInstr);
   895                         msg_address->setInstructionBits(kNopInstr);
   896                     } else {
   897                         printf("Not at debugger stop.\n");
   898                     }
   899                 } else if (argc == 3) {
   900                     // Print information about all/the specified breakpoint(s).
   901                     if (strcmp(arg1, "info") == 0) {
   902                         if (strcmp(arg2, "all") == 0) {
   903                             printf("Stop information:\n");
   904                             for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++)
   905                                 sim_->printStopInfo(i);
   906                         } else if (getValue(arg2, &value)) {
   907                             sim_->printStopInfo(value);
   908                         } else {
   909                             printf("Unrecognized argument.\n");
   910                         }
   911                     } else if (strcmp(arg1, "enable") == 0) {
   912                         // Enable all/the specified breakpoint(s).
   913                         if (strcmp(arg2, "all") == 0) {
   914                             for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++)
   915                                 sim_->enableStop(i);
   916                         } else if (getValue(arg2, &value)) {
   917                             sim_->enableStop(value);
   918                         } else {
   919                             printf("Unrecognized argument.\n");
   920                         }
   921                     } else if (strcmp(arg1, "disable") == 0) {
   922                         // Disable all/the specified breakpoint(s).
   923                         if (strcmp(arg2, "all") == 0) {
   924                             for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
   925                                 sim_->disableStop(i);
   926                             }
   927                         } else if (getValue(arg2, &value)) {
   928                             sim_->disableStop(value);
   929                         } else {
   930                             printf("Unrecognized argument.\n");
   931                         }
   932                     }
   933                 } else {
   934                     printf("Wrong usage. Use help command for more information.\n");
   935                 }
   936             } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
   937                 printf("cont\n");
   938                 printf("  continue execution (alias 'c')\n");
   939                 printf("skip\n");
   940                 printf("  skip one instruction (set pc to next instruction)\n");
   941                 printf("stepi\n");
   942                 printf("  step one instruction (alias 'si')\n");
   943                 printf("print <register>\n");
   944                 printf("  print register content (alias 'p')\n");
   945                 printf("  use register name 'all' to print all registers\n");
   946                 printf("  add argument 'fp' to print register pair double values\n");
   947                 printf("flags\n");
   948                 printf("  print flags\n");
   949                 printf("stack [<words>]\n");
   950                 printf("  dump stack content, default dump 10 words)\n");
   951                 printf("mem <address> [<words>]\n");
   952                 printf("  dump memory content, default dump 10 words)\n");
   953                 printf("disasm [<instructions>]\n");
   954                 printf("disasm [<address/register>]\n");
   955                 printf("disasm [[<address/register>] <instructions>]\n");
   956                 printf("  disassemble code, default is 10 instructions\n");
   957                 printf("  from pc (alias 'di')\n");
   958                 printf("gdb\n");
   959                 printf("  enter gdb\n");
   960                 printf("break <address>\n");
   961                 printf("  set a break point on the address\n");
   962                 printf("del\n");
   963                 printf("  delete the breakpoint\n");
   964                 printf("stop feature:\n");
   965                 printf("  Description:\n");
   966                 printf("    Stops are debug instructions inserted by\n");
   967                 printf("    the Assembler::stop() function.\n");
   968                 printf("    When hitting a stop, the Simulator will\n");
   969                 printf("    stop and and give control to the ArmDebugger.\n");
   970                 printf("    The first %d stop codes are watched:\n",
   971                        Simulator::kNumOfWatchedStops);
   972                 printf("    - They can be enabled / disabled: the Simulator\n");
   973                 printf("      will / won't stop when hitting them.\n");
   974                 printf("    - The Simulator keeps track of how many times they \n");
   975                 printf("      are met. (See the info command.) Going over a\n");
   976                 printf("      disabled stop still increases its counter. \n");
   977                 printf("  Commands:\n");
   978                 printf("    stop info all/<code> : print infos about number <code>\n");
   979                 printf("      or all stop(s).\n");
   980                 printf("    stop enable/disable all/<code> : enables / disables\n");
   981                 printf("      all or number <code> stop(s)\n");
   982                 printf("    stop unstop\n");
   983                 printf("      ignore the stop instruction at the current location\n");
   984                 printf("      from now on\n");
   985             } else {
   986                 printf("Unknown command: %s\n", cmd);
   987             }
   988         }
   989     }
   991     // Add all the breakpoints back to stop execution and enter the debugger
   992     // shell when hit.
   993     redoBreakpoints();
   995 #undef COMMAND_SIZE
   996 #undef ARG_SIZE
   998 #undef STR
   999 #undef XSTR
  1002 static bool
  1003 AllOnOnePage(uintptr_t start, int size)
  1005     intptr_t start_page = (start & ~CachePage::kPageMask);
  1006     intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
  1007     return start_page == end_page;
  1010 static CachePage *
  1011 GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
  1013     MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
  1015     SimulatorRuntime::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
  1016     if (p)
  1017         return p->value();
  1019     CachePage *new_page = js_new<CachePage>();
  1020     if (!i_cache.add(p, page, new_page))
  1021         return nullptr;
  1022     return new_page;
  1025 // Flush from start up to and not including start + size.
  1026 static void
  1027 FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
  1029     MOZ_ASSERT(size <= CachePage::kPageSize);
  1030     MOZ_ASSERT(AllOnOnePage(start, size - 1));
  1031     MOZ_ASSERT((start & CachePage::kLineMask) == 0);
  1032     MOZ_ASSERT((size & CachePage::kLineMask) == 0);
  1034     void *page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
  1035     int offset = (start & CachePage::kPageMask);
  1036     CachePage *cache_page = GetCachePage(i_cache, page);
  1037     char *valid_bytemap = cache_page->validityByte(offset);
  1038     memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
  1041 static void
  1042 FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
  1044     intptr_t start = reinterpret_cast<intptr_t>(start_addr);
  1045     int intra_line = (start & CachePage::kLineMask);
  1046     start -= intra_line;
  1047     size += intra_line;
  1048     size = ((size - 1) | CachePage::kLineMask) + 1;
  1049     int offset = (start & CachePage::kPageMask);
  1050     while (!AllOnOnePage(start, size - 1)) {
  1051         int bytes_to_flush = CachePage::kPageSize - offset;
  1052         FlushOnePage(i_cache, start, bytes_to_flush);
  1053         start += bytes_to_flush;
  1054         size -= bytes_to_flush;
  1055         MOZ_ASSERT((start & CachePage::kPageMask) == 0);
  1056         offset = 0;
  1058     if (size != 0)
  1059         FlushOnePage(i_cache, start, size);
  1062 static void
  1063 CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
  1065     intptr_t address = reinterpret_cast<intptr_t>(instr);
  1066     void *page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
  1067     void *line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
  1068     int offset = (address & CachePage::kPageMask);
  1069     CachePage* cache_page = GetCachePage(i_cache, page);
  1070     char *cache_valid_byte = cache_page->validityByte(offset);
  1071     bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
  1072     char *cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
  1073     if (cache_hit) {
  1074         // Check that the data in memory matches the contents of the I-cache.
  1075         MOZ_ASSERT(memcmp(reinterpret_cast<void*>(instr),
  1076                           cache_page->cachedData(offset),
  1077                           SimInstruction::kInstrSize) == 0);
  1078     } else {
  1079         // Cache miss.  Load memory into the cache.
  1080         memcpy(cached_line, line, CachePage::kLineLength);
  1081         *cache_valid_byte = CachePage::LINE_VALID;
  1085 HashNumber
  1086 SimulatorRuntime::ICacheHasher::hash(const Lookup &l)
  1088     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
  1091 bool
  1092 SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
  1094     MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
  1095     MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
  1096     return k == l;
  1099 void
  1100 Simulator::setLastDebuggerInput(char *input)
  1102     js_free(lastDebuggerInput_);
  1103     lastDebuggerInput_ = input;
  1106 void
  1107 Simulator::FlushICache(void *start_addr, size_t size)
  1109     IonSpewCont(IonSpew_CacheFlush, "[%p %zx]", start_addr, size);
  1110     if (!Simulator::ICacheCheckingEnabled)
  1111         return;
  1112     SimulatorRuntime *srt = Simulator::Current()->srt_;
  1113     AutoLockSimulatorRuntime alsr(srt);
  1114     js::jit::FlushICache(srt->icache(), start_addr, size);
  1117 Simulator::~Simulator()
  1119     js_free(stack_);
  1122 Simulator::Simulator(SimulatorRuntime *srt)
  1123   : srt_(srt)
  1125     // Set up simulator support first. Some of this information is needed to
  1126     // setup the architecture state.
  1128     // Allocate 2MB for the stack. Note that we will only use 1MB, see also
  1129     // Simulator::stackLimit().
  1130     static const size_t stackSize = 2 * 1024*1024;
  1131     stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
  1132     if (!stack_) {
  1133         MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__);
  1134         MOZ_CRASH();
  1136     pc_modified_ = false;
  1137     icount_ = 0L;
  1138     resume_pc_ = 0;
  1139     break_pc_ = nullptr;
  1140     break_instr_ = 0;
  1142     // Set up architecture state.
  1143     // All registers are initialized to zero to start with.
  1144     for (int i = 0; i < num_registers; i++)
  1145         registers_[i] = 0;
  1147     n_flag_ = false;
  1148     z_flag_ = false;
  1149     c_flag_ = false;
  1150     v_flag_ = false;
  1152     for (int i = 0; i < num_d_registers * 2; i++)
  1153         vfp_registers_[i] = 0;
  1155     n_flag_FPSCR_ = false;
  1156     z_flag_FPSCR_ = false;
  1157     c_flag_FPSCR_ = false;
  1158     v_flag_FPSCR_ = false;
  1159     FPSCR_rounding_mode_ = SimRZ;
  1160     FPSCR_default_NaN_mode_ = true;
  1162     inv_op_vfp_flag_ = false;
  1163     div_zero_vfp_flag_ = false;
  1164     overflow_vfp_flag_ = false;
  1165     underflow_vfp_flag_ = false;
  1166     inexact_vfp_flag_ = false;
  1168     // The sp is initialized to point to the bottom (high address) of the
  1169     // allocated stack area. To be safe in potential stack underflows we leave
  1170     // some buffer below.
  1171     registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
  1173     // The lr and pc are initialized to a known bad value that will cause an
  1174     // access violation if the simulator ever tries to execute it.
  1175     registers_[pc] = bad_lr;
  1176     registers_[lr] = bad_lr;
  1178     lastDebuggerInput_ = nullptr;
  1181 // When the generated code calls a VM function (masm.callWithABI) we need to
  1182 // call that function instead of trying to execute it with the simulator
  1183 // (because it's x86 code instead of arm code). We do that by redirecting the
  1184 // VM call to a svc (Supervisor Call) instruction that is handled by the
  1185 // simulator. We write the original destination of the jump just at a known
  1186 // offset from the svc instruction so the simulator knows what to call.
  1187 class Redirection
  1189     friend class SimulatorRuntime;
  1191     Redirection(void *nativeFunction, ABIFunctionType type)
  1192       : nativeFunction_(nativeFunction),
  1193         swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
  1194         type_(type),
  1195         next_(nullptr)
  1197         Simulator *sim = Simulator::Current();
  1198         SimulatorRuntime *srt = sim->srt_;
  1199         next_ = srt->redirection();
  1200         if (Simulator::ICacheCheckingEnabled)
  1201             FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
  1202         srt->setRedirection(this);
  1205   public:
  1206     void *addressOfSwiInstruction() { return &swiInstruction_; }
  1207     void *nativeFunction() const { return nativeFunction_; }
  1208     ABIFunctionType type() const { return type_; }
  1210     static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
  1211         Simulator *sim = Simulator::Current();
  1212         AutoLockSimulatorRuntime alsr(sim->srt_);
  1214         Redirection *current = sim->srt_->redirection();
  1215         for (; current != nullptr; current = current->next_) {
  1216             if (current->nativeFunction_ == nativeFunction) {
  1217                 MOZ_ASSERT(current->type() == type);
  1218                 return current;
  1222         Redirection *redir = (Redirection *)js_malloc(sizeof(Redirection));
  1223         if (!redir) {
  1224             MOZ_ReportAssertionFailure("[unhandlable oom] Simulator redirection",
  1225                                        __FILE__, __LINE__);
  1226             MOZ_CRASH();
  1228         new(redir) Redirection(nativeFunction, type);
  1229         return redir;
  1232     static Redirection *FromSwiInstruction(SimInstruction *swiInstruction) {
  1233         uint8_t *addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
  1234         uint8_t *addrOfRedirection = addrOfSwi - offsetof(Redirection, swiInstruction_);
  1235         return reinterpret_cast<Redirection*>(addrOfRedirection);
  1238   private:
  1239     void *nativeFunction_;
  1240     uint32_t swiInstruction_;
  1241     ABIFunctionType type_;
  1242     Redirection *next_;
  1243 };
  1245 /* static */ void *
  1246 Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
  1248     Redirection *redirection = Redirection::Get(nativeFunction, type);
  1249     return redirection->addressOfSwiInstruction();
  1252 SimulatorRuntime::~SimulatorRuntime()
  1254     Redirection *r = redirection_;
  1255     while (r) {
  1256         Redirection *next = r->next_;
  1257         js_delete(r);
  1258         r = next;
  1260 #ifdef JS_THREADSAFE
  1261     if (lock_)
  1262         PR_DestroyLock(lock_);
  1263 #endif
  1266 // Sets the register in the architecture state. It will also deal with updating
  1267 // Simulator internal state for special registers such as PC.
  1268 void
  1269 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     registers_[reg] = value;
  1277 // Get the register from the architecture state. This function does handle
  1278 // the special case of accessing the PC register.
  1279 int32_t
  1280 Simulator::get_register(int reg) const
  1282     MOZ_ASSERT(reg >= 0 && reg < num_registers);
  1283     // Work around GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
  1284     if (reg >= num_registers) return 0;
  1285     return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
  1288 double
  1289 Simulator::get_double_from_register_pair(int reg)
  1291     MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
  1293     // Read the bits from the unsigned integer register_[] array
  1294     // into the double precision floating point value and return it.
  1295     double dm_val = 0.0;
  1296     char buffer[2 * sizeof(vfp_registers_[0])];
  1297     memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
  1298     memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
  1299     return dm_val;
  1302 void
  1303 Simulator::set_register_pair_from_double(int reg, double *value)
  1305     MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
  1306     memcpy(registers_ + reg, value, sizeof(*value));
  1309 void
  1310 Simulator::set_dw_register(int dreg, const int *dbl)
  1312     MOZ_ASSERT(dreg >= 0 && dreg < num_d_registers);
  1313     registers_[dreg] = dbl[0];
  1314     registers_[dreg + 1] = dbl[1];
  1317 void
  1318 Simulator::get_d_register(int dreg, uint64_t *value)
  1320     MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
  1321     memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
  1324 void
  1325 Simulator::set_d_register(int dreg, const uint64_t *value)
  1327     MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
  1328     memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
  1331 void
  1332 Simulator::get_d_register(int dreg, uint32_t *value)
  1334     MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
  1335     memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
  1338 void
  1339 Simulator::set_d_register(int dreg, const uint32_t *value)
  1341     MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
  1342     memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
  1345 void
  1346 Simulator::get_q_register(int qreg, uint64_t *value)
  1348     MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
  1349     memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
  1352 void
  1353 Simulator::set_q_register(int qreg, const uint64_t *value)
  1355     MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
  1356     memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
  1359 void
  1360 Simulator::get_q_register(int qreg, uint32_t *value)
  1362     MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
  1363     memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
  1366 void
  1367 Simulator::set_q_register(int qreg, const uint32_t *value)
  1369     MOZ_ASSERT((qreg >= 0) && (qreg < num_q_registers));
  1370     memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
  1373 void
  1374 Simulator::set_pc(int32_t value)
  1376     pc_modified_ = true;
  1377     registers_[pc] = value;
  1380 bool
  1381 Simulator::has_bad_pc() const
  1383     return registers_[pc] == bad_lr || registers_[pc] == end_sim_pc;
  1386 // Raw access to the PC register without the special adjustment when reading.
  1387 int32_t
  1388 Simulator::get_pc() const
  1390     return registers_[pc];
  1393 void
  1394 Simulator::set_s_register(int sreg, unsigned int value)
  1396     MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
  1397     vfp_registers_[sreg] = value;
  1400 unsigned
  1401 Simulator::get_s_register(int sreg) const
  1403     MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
  1404     return vfp_registers_[sreg];
  1407 template<class InputType, int register_size>
  1408 void
  1409 Simulator::setVFPRegister(int reg_index, const InputType &value)
  1411     MOZ_ASSERT(reg_index >= 0);
  1412     MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
  1413     MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::Total));
  1415     char buffer[register_size * sizeof(vfp_registers_[0])];
  1416     memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
  1417     memcpy(&vfp_registers_[reg_index * register_size], buffer,
  1418            register_size * sizeof(vfp_registers_[0]));
  1421 template<class ReturnType, int register_size>
  1422 ReturnType Simulator::getFromVFPRegister(int reg_index)
  1424     MOZ_ASSERT(reg_index >= 0);
  1425     MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
  1426     MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::Total));
  1428     ReturnType value = 0;
  1429     char buffer[register_size * sizeof(vfp_registers_[0])];
  1430     memcpy(buffer, &vfp_registers_[register_size * reg_index],
  1431            register_size * sizeof(vfp_registers_[0]));
  1432     memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
  1433     return value;
  1436 void
  1437 Simulator::getFpArgs(double *x, double *y, int32_t *z)
  1439     if (useHardFpABI()) {
  1440         *x = get_double_from_d_register(0);
  1441         *y = get_double_from_d_register(1);
  1442         *z = get_register(0);
  1443     } else {
  1444         *x = get_double_from_register_pair(0);
  1445         *y = get_double_from_register_pair(2);
  1446         *z = get_register(2);
  1450 void
  1451 Simulator::setCallResultDouble(double result)
  1453     // The return value is either in r0/r1 or d0.
  1454     if (useHardFpABI()) {
  1455         char buffer[2 * sizeof(vfp_registers_[0])];
  1456         memcpy(buffer, &result, sizeof(buffer));
  1457         // Copy result to d0.
  1458         memcpy(vfp_registers_, buffer, sizeof(buffer));
  1459     } else {
  1460         char buffer[2 * sizeof(registers_[0])];
  1461         memcpy(buffer, &result, sizeof(buffer));
  1462         // Copy result to r0 and r1.
  1463         memcpy(registers_, buffer, sizeof(buffer));
  1467 void
  1468 Simulator::setCallResultFloat(float result)
  1470     if (useHardFpABI()) {
  1471         char buffer[sizeof(registers_[0])];
  1472         memcpy(buffer, &result, sizeof(buffer));
  1473         // Copy result to s0.
  1474         memcpy(vfp_registers_, buffer, sizeof(buffer));
  1475     } else {
  1476         char buffer[sizeof(registers_[0])];
  1477         memcpy(buffer, &result, sizeof(buffer));
  1478         // Copy result to r0.
  1479         memcpy(registers_, buffer, sizeof(buffer));
  1483 void
  1484 Simulator::setCallResult(int64_t res)
  1486     set_register(r0, static_cast<int32_t>(res));
  1487     set_register(r1, static_cast<int32_t>(res >> 32));
  1490 int
  1491 Simulator::readW(int32_t addr, SimInstruction *instr)
  1493     // YARR emits unaligned loads, so we don't check for them here like the
  1494     // other methods below.
  1495     intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
  1496     return *ptr;
  1499 void
  1500 Simulator::writeW(int32_t addr, int value, SimInstruction *instr)
  1502     if ((addr & 3) == 0) {
  1503         intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
  1504         *ptr = value;
  1505     } else {
  1506         printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
  1507         MOZ_CRASH();
  1511 uint16_t
  1512 Simulator::readHU(int32_t addr, SimInstruction *instr)
  1514     if ((addr & 1) == 0) {
  1515         uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
  1516         return *ptr;
  1518     printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
  1519     MOZ_CRASH();
  1520     return 0;
  1523 int16_t
  1524 Simulator::readH(int32_t addr, SimInstruction *instr)
  1526     if ((addr & 1) == 0) {
  1527         int16_t *ptr = reinterpret_cast<int16_t*>(addr);
  1528         return *ptr;
  1530     printf("Unaligned signed halfword read at 0x%08x\n", addr);
  1531     MOZ_CRASH();
  1532     return 0;
  1535 void
  1536 Simulator::writeH(int32_t addr, uint16_t value, SimInstruction *instr)
  1538     if ((addr & 1) == 0) {
  1539         uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
  1540         *ptr = value;
  1541     } else {
  1542         printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
  1543         MOZ_CRASH();
  1547 void
  1548 Simulator::writeH(int32_t addr, int16_t value, SimInstruction *instr)
  1550     if ((addr & 1) == 0) {
  1551         int16_t *ptr = reinterpret_cast<int16_t*>(addr);
  1552         *ptr = value;
  1553     } else {
  1554         printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
  1555         MOZ_CRASH();
  1559 uint8_t
  1560 Simulator::readBU(int32_t addr)
  1562     uint8_t *ptr = reinterpret_cast<uint8_t*>(addr);
  1563     return *ptr;
  1566 int8_t
  1567 Simulator::readB(int32_t addr)
  1569     int8_t *ptr = reinterpret_cast<int8_t*>(addr);
  1570     return *ptr;
  1573 void
  1574 Simulator::writeB(int32_t addr, uint8_t value)
  1576     uint8_t *ptr = reinterpret_cast<uint8_t*>(addr);
  1577     *ptr = value;
  1580 void
  1581 Simulator::writeB(int32_t addr, int8_t value)
  1583     int8_t *ptr = reinterpret_cast<int8_t*>(addr);
  1584     *ptr = value;
  1587 int32_t *
  1588 Simulator::readDW(int32_t addr)
  1590     if ((addr & 3) == 0) {
  1591         int32_t *ptr = reinterpret_cast<int32_t*>(addr);
  1592         return ptr;
  1594     printf("Unaligned read at 0x%08x\n", addr);
  1595     MOZ_CRASH();
  1596     return 0;
  1599 void
  1600 Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2)
  1602     if ((addr & 3) == 0) {
  1603         int32_t *ptr = reinterpret_cast<int32_t*>(addr);
  1604         *ptr++ = value1;
  1605         *ptr = value2;
  1606     } else {
  1607         printf("Unaligned write at 0x%08x\n", addr);
  1608         MOZ_CRASH();
  1612 uintptr_t
  1613 Simulator::stackLimit() const
  1615     // Leave a safety margin of 1MB to prevent overrunning the stack when
  1616     // pushing values (total stack size is 2MB).
  1617     return reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
  1620 bool
  1621 Simulator::overRecursed(uintptr_t newsp) const
  1623     if (newsp == 0)
  1624         newsp = get_register(sp);
  1625     return newsp <= stackLimit();
  1628 bool
  1629 Simulator::overRecursedWithExtra(uint32_t extra) const
  1631     uintptr_t newsp = get_register(sp) - extra;
  1632     return newsp <= stackLimit();
  1635 // Checks if the current instruction should be executed based on its
  1636 // condition bits.
  1637 bool
  1638 Simulator::conditionallyExecute(SimInstruction *instr)
  1640     switch (instr->conditionField()) {
  1641       case Assembler::EQ: return z_flag_;
  1642       case Assembler::NE: return !z_flag_;
  1643       case Assembler::CS: return c_flag_;
  1644       case Assembler::CC: return !c_flag_;
  1645       case Assembler::MI: return n_flag_;
  1646       case Assembler::PL: return !n_flag_;
  1647       case Assembler::VS: return v_flag_;
  1648       case Assembler::VC: return !v_flag_;
  1649       case Assembler::HI: return c_flag_ && !z_flag_;
  1650       case Assembler::LS: return !c_flag_ || z_flag_;
  1651       case Assembler::GE: return n_flag_ == v_flag_;
  1652       case Assembler::LT: return n_flag_ != v_flag_;
  1653       case Assembler::GT: return !z_flag_ && (n_flag_ == v_flag_);
  1654       case Assembler::LE: return z_flag_ || (n_flag_ != v_flag_);
  1655       case Assembler::AL: return true;
  1656       default: MOZ_ASSUME_UNREACHABLE();
  1658     return false;
  1661 // Calculate and set the Negative and Zero flags.
  1662 void
  1663 Simulator::setNZFlags(int32_t val)
  1665     n_flag_ = (val < 0);
  1666     z_flag_ = (val == 0);
  1669 // Set the Carry flag.
  1670 void
  1671 Simulator::setCFlag(bool val)
  1673     c_flag_ = val;
  1676 // Set the oVerflow flag.
  1677 void
  1678 Simulator::setVFlag(bool val)
  1680     v_flag_ = val;
  1683 // Calculate C flag value for additions.
  1684 bool
  1685 Simulator::carryFrom(int32_t left, int32_t right, int32_t carry)
  1687     uint32_t uleft = static_cast<uint32_t>(left);
  1688     uint32_t uright = static_cast<uint32_t>(right);
  1689     uint32_t urest  = 0xffffffffU - uleft;
  1690     return (uright > urest) ||
  1691            (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
  1694 // Calculate C flag value for subtractions.
  1695 bool
  1696 Simulator::borrowFrom(int32_t left, int32_t right)
  1698     uint32_t uleft = static_cast<uint32_t>(left);
  1699     uint32_t uright = static_cast<uint32_t>(right);
  1700     return (uright > uleft);
  1703 // Calculate V flag value for additions and subtractions.
  1704 bool
  1705 Simulator::overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition)
  1707     bool overflow;
  1708     if (addition) {
  1709         // operands have the same sign
  1710         overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
  1711             // and operands and result have different sign
  1712             && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
  1713     } else {
  1714         // operands have different signs
  1715         overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
  1716             // and first operand and result have different signs
  1717             && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
  1719     return overflow;
  1722 // Support for VFP comparisons.
  1723 void
  1724 Simulator::compute_FPSCR_Flags(double val1, double val2)
  1726     if (mozilla::IsNaN(val1) || mozilla::IsNaN(val2)) {
  1727         n_flag_FPSCR_ = false;
  1728         z_flag_FPSCR_ = false;
  1729         c_flag_FPSCR_ = true;
  1730         v_flag_FPSCR_ = true;
  1731         // All non-NaN cases.
  1732     } else if (val1 == val2) {
  1733         n_flag_FPSCR_ = false;
  1734         z_flag_FPSCR_ = true;
  1735         c_flag_FPSCR_ = true;
  1736         v_flag_FPSCR_ = false;
  1737     } else if (val1 < val2) {
  1738         n_flag_FPSCR_ = true;
  1739         z_flag_FPSCR_ = false;
  1740         c_flag_FPSCR_ = false;
  1741         v_flag_FPSCR_ = false;
  1742     } else {
  1743         // Case when (val1 > val2).
  1744         n_flag_FPSCR_ = false;
  1745         z_flag_FPSCR_ = false;
  1746         c_flag_FPSCR_ = true;
  1747         v_flag_FPSCR_ = false;
  1751 void
  1752 Simulator::copy_FPSCR_to_APSR()
  1754     n_flag_ = n_flag_FPSCR_;
  1755     z_flag_ = z_flag_FPSCR_;
  1756     c_flag_ = c_flag_FPSCR_;
  1757     v_flag_ = v_flag_FPSCR_;
  1760 // Addressing Mode 1 - Data-processing operands:
  1761 // Get the value based on the shifter_operand with register.
  1762 int32_t
  1763 Simulator::getShiftRm(SimInstruction *instr, bool *carry_out)
  1765     ShiftType shift = instr->shifttypeValue();
  1766     int shift_amount = instr->shiftAmountValue();
  1767     int32_t result = get_register(instr->rmValue());
  1768     if (instr->bit(4) == 0) {
  1769         // By immediate.
  1770         if (shift == ROR && shift_amount == 0) {
  1771             MOZ_ASSUME_UNREACHABLE("NYI");
  1772             return result;
  1774         if ((shift == LSR || shift == ASR) && shift_amount == 0)
  1775             shift_amount = 32;
  1776         switch (shift) {
  1777           case ASR: {
  1778             if (shift_amount == 0) {
  1779                 if (result < 0) {
  1780                     result = 0xffffffff;
  1781                     *carry_out = true;
  1782                 } else {
  1783                     result = 0;
  1784                     *carry_out = false;
  1786             } else {
  1787                 result >>= (shift_amount - 1);
  1788                 *carry_out = (result & 1) == 1;
  1789                 result >>= 1;
  1791             break;
  1794           case LSL: {
  1795             if (shift_amount == 0) {
  1796                 *carry_out = c_flag_;
  1797             } else {
  1798                 result <<= (shift_amount - 1);
  1799                 *carry_out = (result < 0);
  1800                 result <<= 1;
  1802             break;
  1805           case LSR: {
  1806             if (shift_amount == 0) {
  1807                 result = 0;
  1808                 *carry_out = c_flag_;
  1809             } else {
  1810                 uint32_t uresult = static_cast<uint32_t>(result);
  1811                 uresult >>= (shift_amount - 1);
  1812                 *carry_out = (uresult & 1) == 1;
  1813                 uresult >>= 1;
  1814                 result = static_cast<int32_t>(uresult);
  1816             break;
  1819           case ROR: {
  1820             if (shift_amount == 0) {
  1821                 *carry_out = c_flag_;
  1822             } else {
  1823                 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
  1824                 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
  1825                 result = right | left;
  1826                 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
  1828             break;
  1831           default:
  1832             MOZ_ASSUME_UNREACHABLE();
  1833             break;
  1835     } else {
  1836         // By register.
  1837         int rs = instr->rsValue();
  1838         shift_amount = get_register(rs) &0xff;
  1839         switch (shift) {
  1840           case ASR: {
  1841             if (shift_amount == 0) {
  1842                 *carry_out = c_flag_;
  1843             } else if (shift_amount < 32) {
  1844                 result >>= (shift_amount - 1);
  1845                 *carry_out = (result & 1) == 1;
  1846                 result >>= 1;
  1847             } else {
  1848                 MOZ_ASSERT(shift_amount >= 32);
  1849                 if (result < 0) {
  1850                     *carry_out = true;
  1851                     result = 0xffffffff;
  1852                 } else {
  1853                     *carry_out = false;
  1854                     result = 0;
  1857             break;
  1860           case LSL: {
  1861             if (shift_amount == 0) {
  1862                 *carry_out = c_flag_;
  1863             } else if (shift_amount < 32) {
  1864                 result <<= (shift_amount - 1);
  1865                 *carry_out = (result < 0);
  1866                 result <<= 1;
  1867             } else if (shift_amount == 32) {
  1868                 *carry_out = (result & 1) == 1;
  1869                 result = 0;
  1870             } else {
  1871                 MOZ_ASSERT(shift_amount > 32);
  1872                 *carry_out = false;
  1873                 result = 0;
  1875             break;
  1878           case LSR: {
  1879             if (shift_amount == 0) {
  1880                 *carry_out = c_flag_;
  1881             } else if (shift_amount < 32) {
  1882                 uint32_t uresult = static_cast<uint32_t>(result);
  1883                 uresult >>= (shift_amount - 1);
  1884                 *carry_out = (uresult & 1) == 1;
  1885                 uresult >>= 1;
  1886                 result = static_cast<int32_t>(uresult);
  1887             } else if (shift_amount == 32) {
  1888                 *carry_out = (result < 0);
  1889                 result = 0;
  1890             } else {
  1891                 *carry_out = false;
  1892                 result = 0;
  1894             break;
  1897           case ROR: {
  1898             if (shift_amount == 0) {
  1899                 *carry_out = c_flag_;
  1900             } else {
  1901                 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
  1902                 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
  1903                 result = right | left;
  1904                 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
  1906             break;
  1909           default:
  1910             MOZ_ASSUME_UNREACHABLE();
  1911             break;
  1914     return result;
  1917 // Addressing Mode 1 - Data-processing operands:
  1918 // Get the value based on the shifter_operand with immediate.
  1919 int32_t
  1920 Simulator::getImm(SimInstruction *instr, bool *carry_out)
  1922     int rotate = instr->rotateValue() * 2;
  1923     int immed8 = instr->immed8Value();
  1924     int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
  1925     *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
  1926     return imm;
  1929 int32_t
  1930 Simulator::processPU(SimInstruction *instr, int num_regs, int reg_size,
  1931                      intptr_t *start_address, intptr_t *end_address)
  1933     int rn = instr->rnValue();
  1934     int32_t rn_val = get_register(rn);
  1935     switch (instr->PUField()) {
  1936       case da_x:
  1937         MOZ_CRASH();
  1938         break;
  1939       case ia_x:
  1940         *start_address = rn_val;
  1941         *end_address = rn_val + (num_regs * reg_size) - reg_size;
  1942         rn_val = rn_val + (num_regs * reg_size);
  1943         break;
  1944       case db_x:
  1945         *start_address = rn_val - (num_regs * reg_size);
  1946         *end_address = rn_val - reg_size;
  1947         rn_val = *start_address;
  1948         break;
  1949       case ib_x:
  1950         *start_address = rn_val + reg_size;
  1951         *end_address = rn_val + (num_regs * reg_size);
  1952         rn_val = *end_address;
  1953         break;
  1954       default:
  1955         MOZ_ASSUME_UNREACHABLE();
  1956         break;
  1958     return rn_val;
  1961 // Addressing Mode 4 - Load and Store Multiple
  1962 void
  1963 Simulator::handleRList(SimInstruction *instr, bool load)
  1965     int rlist = instr->rlistValue();
  1966     int num_regs = mozilla::CountPopulation32(rlist);
  1968     intptr_t start_address = 0;
  1969     intptr_t end_address = 0;
  1970     int32_t rn_val = processPU(instr, num_regs, sizeof(void *), &start_address, &end_address);
  1971     intptr_t *address = reinterpret_cast<intptr_t*>(start_address);
  1973     // Catch null pointers a little earlier.
  1974     MOZ_ASSERT(start_address > 8191 || start_address < 0);
  1976     int reg = 0;
  1977     while (rlist != 0) {
  1978         if ((rlist & 1) != 0) {
  1979             if (load) {
  1980                 set_register(reg, *address);
  1981             } else {
  1982                 *address = get_register(reg);
  1984             address += 1;
  1986         reg++;
  1987         rlist >>= 1;
  1989     MOZ_ASSERT(end_address == ((intptr_t)address) - 4);
  1990     if (instr->hasW())
  1991         set_register(instr->rnValue(), rn_val);
  1994 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
  1995 void
  1996 Simulator::handleVList(SimInstruction *instr)
  1998     VFPRegPrecision precision = (instr->szValue() == 0) ? kSinglePrecision : kDoublePrecision;
  1999     int operand_size = (precision == kSinglePrecision) ? 4 : 8;
  2000     bool load = (instr->VLValue() == 0x1);
  2002     int vd;
  2003     int num_regs;
  2004     vd = instr->VFPDRegValue(precision);
  2005     if (precision == kSinglePrecision)
  2006         num_regs = instr->immed8Value();
  2007     else
  2008         num_regs = instr->immed8Value() / 2;
  2010     intptr_t start_address = 0;
  2011     intptr_t end_address = 0;
  2012     int32_t rn_val = processPU(instr, num_regs, operand_size, &start_address, &end_address);
  2014     intptr_t *address = reinterpret_cast<intptr_t*>(start_address);
  2015     for (int reg = vd; reg < vd + num_regs; reg++) {
  2016         if (precision == kSinglePrecision) {
  2017             if (load)
  2018                 set_s_register_from_sinteger(reg, readW(reinterpret_cast<int32_t>(address), instr));
  2019             else
  2020                 writeW(reinterpret_cast<int32_t>(address), get_sinteger_from_s_register(reg), instr);
  2021             address += 1;
  2022         } else {
  2023             if (load) {
  2024                 int32_t data[] = {
  2025                     readW(reinterpret_cast<int32_t>(address), instr),
  2026                     readW(reinterpret_cast<int32_t>(address + 1), instr)
  2027                 };
  2028                 double d;
  2029                 memcpy(&d, data, 8);
  2030                 set_d_register_from_double(reg, d);
  2031             } else {
  2032                 int32_t data[2];
  2033                 double d = get_double_from_d_register(reg);
  2034                 memcpy(data, &d, 8);
  2035                 writeW(reinterpret_cast<int32_t>(address), data[0], instr);
  2036                 writeW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
  2038             address += 2;
  2041     MOZ_ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
  2042     if (instr->hasW())
  2043         set_register(instr->rnValue(), rn_val);
  2047 // Note: With the code below we assume that all runtime calls return a 64 bits
  2048 // result. If they don't, the r1 result register contains a bogus value, which
  2049 // is fine because it is caller-saved.
  2050 typedef int64_t (*Prototype_General0)();
  2051 typedef int64_t (*Prototype_General1)(int32_t arg0);
  2052 typedef int64_t (*Prototype_General2)(int32_t arg0, int32_t arg1);
  2053 typedef int64_t (*Prototype_General3)(int32_t arg0, int32_t arg1, int32_t arg2);
  2054 typedef int64_t (*Prototype_General4)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3);
  2055 typedef int64_t (*Prototype_General5)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
  2056                                       int32_t arg4);
  2057 typedef int64_t (*Prototype_General6)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
  2058                                       int32_t arg4, int32_t arg5);
  2059 typedef int64_t (*Prototype_General7)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
  2060                                       int32_t arg4, int32_t arg5, int32_t arg6);
  2061 typedef int64_t (*Prototype_General8)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
  2062                                       int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7);
  2064 typedef double (*Prototype_Double_None)();
  2065 typedef double (*Prototype_Double_Double)(double arg0);
  2066 typedef double (*Prototype_Double_Int)(int32_t arg0);
  2067 typedef int32_t (*Prototype_Int_Double)(double arg0);
  2068 typedef float (*Prototype_Float32_Float32)(float arg0);
  2070 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
  2071 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
  2072 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
  2073 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
  2076 // Fill the volatile registers with scratch values.
  2077 //
  2078 // Some of the ABI calls assume that the float registers are not scratched, even
  2079 // though the ABI defines them as volatile - a performance optimization.  These are
  2080 // all calls passing operands in integer registers, so for now the simulator does not
  2081 // scratch any float registers for these calls.  Should try to narrow it further in
  2082 // future.
  2083 //
  2084 void
  2085 Simulator::scratchVolatileRegisters(bool scratchFloat)
  2087     int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
  2088     set_register(r0, scratch_value);
  2089     set_register(r1, scratch_value);
  2090     set_register(r2, scratch_value);
  2091     set_register(r3, scratch_value);
  2092     set_register(r12, scratch_value); // Intra-Procedure-call scratch register
  2093     set_register(r14, scratch_value); // Link register
  2095     if (scratchFloat) {
  2096         uint64_t scratch_value_d = 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
  2097         for (uint32_t i = d0; i < d8; i++)
  2098             set_d_register(i, &scratch_value_d);
  2099         for (uint32_t i = d16; i < FloatRegisters::Total; i++)
  2100             set_d_register(i, &scratch_value_d);
  2104 // Software interrupt instructions are used by the simulator to call into C++.
  2105 void
  2106 Simulator::softwareInterrupt(SimInstruction *instr)
  2108     int svc = instr->svcValue();
  2109     switch (svc) {
  2110       case kCallRtRedirected: {
  2111         Redirection *redirection = Redirection::FromSwiInstruction(instr);
  2112         int32_t arg0 = get_register(r0);
  2113         int32_t arg1 = get_register(r1);
  2114         int32_t arg2 = get_register(r2);
  2115         int32_t arg3 = get_register(r3);
  2116         int32_t *stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
  2117         int32_t arg4 = stack_pointer[0];
  2118         int32_t arg5 = stack_pointer[1];
  2120         int32_t saved_lr = get_register(lr);
  2121         intptr_t external = reinterpret_cast<intptr_t>(redirection->nativeFunction());
  2123         bool stack_aligned = (get_register(sp) & (StackAlignment - 1)) == 0;
  2124         if (!stack_aligned) {
  2125             fprintf(stderr, "Runtime call with unaligned stack!\n");
  2126             MOZ_CRASH();
  2129         switch (redirection->type()) {
  2130           case Args_General0: {
  2131             Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
  2132             int64_t result = target();
  2133             scratchVolatileRegisters(/* scratchFloat = true */);
  2134             setCallResult(result);
  2135             break;
  2137           case Args_General1: {
  2138             Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
  2139             int64_t result = target(arg0);
  2140             scratchVolatileRegisters(/* scratchFloat = true */);
  2141             setCallResult(result);
  2142             break;
  2144           case Args_General2: {
  2145             Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
  2146             int64_t result = target(arg0, arg1);
  2147             // The ARM backend makes calls to __aeabi_idivmod and __aeabi_uidivmod assuming
  2148             // that the float registers are non-volatile as a performance optimization, so the
  2149             // float registers must not be scratch when calling these.
  2150             bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
  2151             scratchVolatileRegisters(/* scratchFloat = */ scratchFloat);
  2152             setCallResult(result);
  2153             break;
  2155           case Args_General3: {
  2156             Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
  2157             int64_t result = target(arg0, arg1, arg2);
  2158             scratchVolatileRegisters(/* scratchFloat = true*/);
  2159             setCallResult(result);
  2160             break;
  2162           case Args_General4: {
  2163             Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
  2164             int64_t result = target(arg0, arg1, arg2, arg3);
  2165             scratchVolatileRegisters(/* scratchFloat = true*/);
  2166             setCallResult(result);
  2167             break;
  2169           case Args_General5: {
  2170             Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
  2171             int64_t result = target(arg0, arg1, arg2, arg3, arg4);
  2172             scratchVolatileRegisters(/* scratchFloat = true */);
  2173             setCallResult(result);
  2174             break;
  2176           case Args_General6: {
  2177             Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
  2178             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
  2179             scratchVolatileRegisters(/* scratchFloat = true */);
  2180             setCallResult(result);
  2181             break;
  2183           case Args_General7: {
  2184             Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
  2185             int32_t arg6 = stack_pointer[2];
  2186             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
  2187             scratchVolatileRegisters(/* scratchFloat = true */);
  2188             setCallResult(result);
  2189             break;
  2191           case Args_General8: {
  2192             Prototype_General8 target = reinterpret_cast<Prototype_General8>(external);
  2193             int32_t arg6 = stack_pointer[2];
  2194             int32_t arg7 = stack_pointer[3];
  2195             int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
  2196             scratchVolatileRegisters(/* scratchFloat = true */);
  2197             setCallResult(result);
  2198             break;
  2200           case Args_Double_None: {
  2201             Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
  2202             double dresult = target();
  2203             scratchVolatileRegisters(/* scratchFloat = true */);
  2204             setCallResultDouble(dresult);
  2205             break;
  2207           case Args_Int_Double: {
  2208             double dval0, dval1;
  2209             int32_t ival;
  2210             getFpArgs(&dval0, &dval1, &ival);
  2211             Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
  2212             int32_t res = target(dval0);
  2213             scratchVolatileRegisters(/* scratchFloat = true */);
  2214             set_register(r0, res);
  2215             break;
  2217           case Args_Double_Double: {
  2218             double dval0, dval1;
  2219             int32_t ival;
  2220             getFpArgs(&dval0, &dval1, &ival);
  2221             Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
  2222             double dresult = target(dval0);
  2223             scratchVolatileRegisters(/* scratchFloat = true */);
  2224             setCallResultDouble(dresult);
  2225             break;
  2227           case Args_Float32_Float32: {
  2228             float fval0;
  2229             if (useHardFpABI())
  2230                 fval0 = get_float_from_s_register(0);
  2231             else
  2232                 fval0 = mozilla::BitwiseCast<float>(arg0);
  2233             Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
  2234             float fresult = target(fval0);
  2235             scratchVolatileRegisters(/* scratchFloat = true */);
  2236             setCallResultFloat(fresult);
  2237             break;
  2239           case Args_Double_Int: {
  2240             Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
  2241             double dresult = target(arg0);
  2242             scratchVolatileRegisters(/* scratchFloat = true */);
  2243             setCallResultDouble(dresult);
  2244             break;
  2246           case Args_Double_DoubleInt: {
  2247             double dval0, dval1;
  2248             int32_t ival;
  2249             getFpArgs(&dval0, &dval1, &ival);
  2250             Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
  2251             double dresult = target(dval0, ival);
  2252             scratchVolatileRegisters(/* scratchFloat = true */);
  2253             setCallResultDouble(dresult);
  2254             break;
  2256           case Args_Double_DoubleDouble: {
  2257             double dval0, dval1;
  2258             int32_t ival;
  2259             getFpArgs(&dval0, &dval1, &ival);
  2260             Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
  2261             double dresult = target(dval0, dval1);
  2262             scratchVolatileRegisters(/* scratchFloat = true */);
  2263             setCallResultDouble(dresult);
  2264             break;
  2266           case Args_Double_IntDouble: {
  2267             int32_t ival = get_register(0);
  2268             double dval0;
  2269             if (useHardFpABI())
  2270                 dval0 = get_double_from_d_register(0);
  2271             else
  2272                 dval0 = get_double_from_register_pair(2);
  2273             Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
  2274             double dresult = target(ival, dval0);
  2275             scratchVolatileRegisters(/* scratchFloat = true */);
  2276             setCallResultDouble(dresult);
  2277             break;
  2279           case Args_Int_IntDouble: {
  2280             int32_t ival = get_register(0);
  2281             double dval0;
  2282             if (useHardFpABI())
  2283                 dval0 = get_double_from_d_register(0);
  2284             else
  2285                 dval0 = get_double_from_register_pair(2);
  2286             Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
  2287             int32_t result = target(ival, dval0);
  2288             scratchVolatileRegisters(/* scratchFloat = true */);
  2289             set_register(r0, result);
  2290             break;
  2292           default:
  2293             MOZ_ASSUME_UNREACHABLE("call");
  2296         set_register(lr, saved_lr);
  2297         set_pc(get_register(lr));
  2298         break;
  2300       case kBreakpoint: {
  2301         ArmDebugger dbg(this);
  2302         dbg.debug();
  2303         break;
  2305       default: { // Stop uses all codes greater than 1 << 23.
  2306         if (svc >= (1 << 23)) {
  2307             uint32_t code = svc & kStopCodeMask;
  2308             if (isWatchedStop(code))
  2309                 increaseStopCounter(code);
  2311             // Stop if it is enabled, otherwise go on jumping over the stop
  2312             // and the message address.
  2313             if (isEnabledStop(code)) {
  2314                 ArmDebugger dbg(this);
  2315                 dbg.stop(instr);
  2316             } else {
  2317                 set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
  2319         } else {
  2320             // This is not a valid svc code.
  2321             MOZ_CRASH();
  2322             break;
  2328 double
  2329 Simulator::canonicalizeNaN(double value)
  2331     return FPSCR_default_NaN_mode_ ? JS::CanonicalizeNaN(value) : value;
  2334 // Stop helper functions.
  2335 bool
  2336 Simulator::isStopInstruction(SimInstruction *instr)
  2338     return (instr->bits(27, 24) == 0xF) && (instr->svcValue() >= kStopCode);
  2341 bool Simulator::isWatchedStop(uint32_t code)
  2343     MOZ_ASSERT(code <= kMaxStopCode);
  2344     return code < kNumOfWatchedStops;
  2347 bool
  2348 Simulator::isEnabledStop(uint32_t code)
  2350     MOZ_ASSERT(code <= kMaxStopCode);
  2351     // Unwatched stops are always enabled.
  2352     return !isWatchedStop(code) || !(watched_stops_[code].count & kStopDisabledBit);
  2355 void
  2356 Simulator::enableStop(uint32_t code)
  2358     MOZ_ASSERT(isWatchedStop(code));
  2359     if (!isEnabledStop(code))
  2360         watched_stops_[code].count &= ~kStopDisabledBit;
  2363 void
  2364 Simulator::disableStop(uint32_t code)
  2366     MOZ_ASSERT(isWatchedStop(code));
  2367     if (isEnabledStop(code))
  2368         watched_stops_[code].count |= kStopDisabledBit;
  2371 void
  2372 Simulator::increaseStopCounter(uint32_t code)
  2374     MOZ_ASSERT(code <= kMaxStopCode);
  2375     MOZ_ASSERT(isWatchedStop(code));
  2376     if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
  2377         printf("Stop counter for code %i has overflowed.\n"
  2378                "Enabling this code and reseting the counter to 0.\n", code);
  2379         watched_stops_[code].count = 0;
  2380         enableStop(code);
  2381     } else {
  2382         watched_stops_[code].count++;
  2386 // Print a stop status.
  2387 void
  2388 Simulator::printStopInfo(uint32_t code)
  2390     MOZ_ASSERT(code <= kMaxStopCode);
  2391     if (!isWatchedStop(code)) {
  2392         printf("Stop not watched.");
  2393     } else {
  2394         const char *state = isEnabledStop(code) ? "Enabled" : "Disabled";
  2395         int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
  2396         // Don't print the state of unused breakpoints.
  2397         if (count != 0) {
  2398             if (watched_stops_[code].desc) {
  2399                 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
  2400                        code, code, state, count, watched_stops_[code].desc);
  2401             } else {
  2402                 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n",
  2403                        code, code, state, count);
  2409 // Instruction types 0 and 1 are both rolled into one function because they
  2410 // only differ in the handling of the shifter_operand.
  2411 void
  2412 Simulator::decodeType01(SimInstruction *instr)
  2414     int type = instr->typeValue();
  2415     if (type == 0 && instr->isSpecialType0()) {
  2416         // Multiply instruction or extra loads and stores.
  2417         if (instr->bits(7, 4) == 9) {
  2418             if (instr->bit(24) == 0) {
  2419                 // Raw field decoding here. Multiply instructions have their Rd
  2420                 // in funny places.
  2421                 int rn = instr->rnValue();
  2422                 int rm = instr->rmValue();
  2423                 int rs = instr->rsValue();
  2424                 int32_t rs_val = get_register(rs);
  2425                 int32_t rm_val = get_register(rm);
  2426                 if (instr->bit(23) == 0) {
  2427                     if (instr->bit(21) == 0) {
  2428                         // The MUL instruction description (A 4.1.33) refers to Rd as being
  2429                         // the destination for the operation, but it confusingly uses the
  2430                         // Rn field to encode it.
  2431                         int rd = rn;  // Remap the rn field to the Rd register.
  2432                         int32_t alu_out = rm_val * rs_val;
  2433                         set_register(rd, alu_out);
  2434                         if (instr->hasS())
  2435                             setNZFlags(alu_out);
  2436                     } else {
  2437                         int rd = instr->rdValue();
  2438                         int32_t acc_value = get_register(rd);
  2439                         if (instr->bit(22) == 0) {
  2440                             // The MLA instruction description (A 4.1.28) refers to the order
  2441                             // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
  2442                             // Rn field to encode the Rd register and the Rd field to encode
  2443                             // the Rn register.
  2444                             int32_t mul_out = rm_val * rs_val;
  2445                             int32_t result = acc_value + mul_out;
  2446                             set_register(rn, result);
  2447                         } else {
  2448                             int32_t mul_out = rm_val * rs_val;
  2449                             int32_t result = acc_value - mul_out;
  2450                             set_register(rn, result);
  2453                 } else {
  2454                     // The signed/long multiply instructions use the terms RdHi and RdLo
  2455                     // when referring to the target registers. They are mapped to the Rn
  2456                     // and Rd fields as follows:
  2457                     // RdLo == Rd
  2458                     // RdHi == Rn (This is confusingly stored in variable rd here
  2459                     //             because the mul instruction from above uses the
  2460                     //             Rn field to encode the Rd register. Good luck figuring
  2461                     //             this out without reading the ARM instruction manual
  2462                     //             at a very detailed level.)
  2463                     int rd_hi = rn;  // Remap the rn field to the RdHi register.
  2464                     int rd_lo = instr->rdValue();
  2465                     int32_t hi_res = 0;
  2466                     int32_t lo_res = 0;
  2467                     if (instr->bit(22) == 1) {
  2468                         int64_t left_op  = static_cast<int32_t>(rm_val);
  2469                         int64_t right_op = static_cast<int32_t>(rs_val);
  2470                         uint64_t result = left_op * right_op;
  2471                         hi_res = static_cast<int32_t>(result >> 32);
  2472                         lo_res = static_cast<int32_t>(result & 0xffffffff);
  2473                     } else {
  2474                         // unsigned multiply
  2475                         uint64_t left_op  = static_cast<uint32_t>(rm_val);
  2476                         uint64_t right_op = static_cast<uint32_t>(rs_val);
  2477                         uint64_t result = left_op * right_op;
  2478                         hi_res = static_cast<int32_t>(result >> 32);
  2479                         lo_res = static_cast<int32_t>(result & 0xffffffff);
  2481                     set_register(rd_lo, lo_res);
  2482                     set_register(rd_hi, hi_res);
  2483                     if (instr->hasS())
  2484                         MOZ_CRASH();
  2486             } else {
  2487                 MOZ_CRASH(); // Not used atm.
  2489         } else {
  2490             // extra load/store instructions
  2491             int rd = instr->rdValue();
  2492             int rn = instr->rnValue();
  2493             int32_t rn_val = get_register(rn);
  2494             int32_t addr = 0;
  2495             if (instr->bit(22) == 0) {
  2496                 int rm = instr->rmValue();
  2497                 int32_t rm_val = get_register(rm);
  2498                 switch (instr->PUField()) {
  2499                   case da_x:
  2500                     MOZ_ASSERT(!instr->hasW());
  2501                     addr = rn_val;
  2502                     rn_val -= rm_val;
  2503                     set_register(rn, rn_val);
  2504                     break;
  2505                   case ia_x:
  2506                     MOZ_ASSERT(!instr->hasW());
  2507                     addr = rn_val;
  2508                     rn_val += rm_val;
  2509                     set_register(rn, rn_val);
  2510                     break;
  2511                   case db_x:
  2512                     rn_val -= rm_val;
  2513                     addr = rn_val;
  2514                     if (instr->hasW())
  2515                         set_register(rn, rn_val);
  2516                     break;
  2517                   case ib_x:
  2518                     rn_val += rm_val;
  2519                     addr = rn_val;
  2520                     if (instr->hasW())
  2521                         set_register(rn, rn_val);
  2522                     break;
  2523                   default:
  2524                     // The PU field is a 2-bit field.
  2525                     MOZ_CRASH();
  2526                     break;
  2528             } else {
  2529                 int32_t imm_val = (instr->immedHValue() << 4) | instr->immedLValue();
  2530                 switch (instr->PUField()) {
  2531                   case da_x:
  2532                     MOZ_ASSERT(!instr->hasW());
  2533                     addr = rn_val;
  2534                     rn_val -= imm_val;
  2535                     set_register(rn, rn_val);
  2536                     break;
  2537                   case ia_x:
  2538                     MOZ_ASSERT(!instr->hasW());
  2539                     addr = rn_val;
  2540                     rn_val += imm_val;
  2541                     set_register(rn, rn_val);
  2542                     break;
  2543                   case db_x:
  2544                     rn_val -= imm_val;
  2545                     addr = rn_val;
  2546                     if (instr->hasW())
  2547                         set_register(rn, rn_val);
  2548                     break;
  2549                   case ib_x:
  2550                     rn_val += imm_val;
  2551                     addr = rn_val;
  2552                     if (instr->hasW())
  2553                         set_register(rn, rn_val);
  2554                     break;
  2555                   default:
  2556                     // The PU field is a 2-bit field.
  2557                     MOZ_CRASH();
  2558                     break;
  2561             if ((instr->bits(7, 4) & 0xd) == 0xd && instr->bit(20) == 0) {
  2562                 MOZ_ASSERT((rd % 2) == 0);
  2563                 if (instr->hasH()) {
  2564                     // The strd instruction.
  2565                     int32_t value1 = get_register(rd);
  2566                     int32_t value2 = get_register(rd+1);
  2567                     writeDW(addr, value1, value2);
  2568                 } else {
  2569                     // The ldrd instruction.
  2570                     int *rn_data = readDW(addr);
  2571                     set_dw_register(rd, rn_data);
  2573             } else if (instr->hasH()) {
  2574                 if (instr->hasSign()) {
  2575                     if (instr->hasL()) {
  2576                         int16_t val = readH(addr, instr);
  2577                         set_register(rd, val);
  2578                     } else {
  2579                         int16_t val = get_register(rd);
  2580                         writeH(addr, val, instr);
  2582                 } else {
  2583                     if (instr->hasL()) {
  2584                         uint16_t val = readHU(addr, instr);
  2585                         set_register(rd, val);
  2586                     } else {
  2587                         uint16_t val = get_register(rd);
  2588                         writeH(addr, val, instr);
  2591             } else {
  2592                 // signed byte loads
  2593                 MOZ_ASSERT(instr->hasSign());
  2594                 MOZ_ASSERT(instr->hasL());
  2595                 int8_t val = readB(addr);
  2596                 set_register(rd, val);
  2598             return;
  2600     } else if ((type == 0) && instr->isMiscType0()) {
  2601         if (instr->bits(7, 4) == 0) {
  2602             if (instr->bit(21) == 0) {
  2603                 // mrs
  2604                 int rd = instr->rdValue();
  2605                 uint32_t flags;
  2606                 if (instr->bit(22) == 0) {
  2607                     // CPSR. Note: The Q flag is not yet implemented!
  2608                     flags = (n_flag_ << 31) |
  2609                         (z_flag_ << 30) |
  2610                         (c_flag_ << 29) |
  2611                         (v_flag_ << 28);
  2612                 } else {
  2613                     // SPSR
  2614                     MOZ_CRASH();
  2616                 set_register(rd, flags);
  2617             } else {
  2618                 // msr
  2619                 if (instr->bits(27, 23) == 2) {
  2620                     // Register operand. For now we only emit mask 0b1100.
  2621                     int rm = instr->rmValue();
  2622                     uint32_t mask = instr->bits(19, 16);
  2623                     MOZ_ASSERT(mask == (3 << 2));
  2625                     uint32_t flags = get_register(rm);
  2626                     n_flag_ = (flags >> 31) & 1;
  2627                     z_flag_ = (flags >> 30) & 1;
  2628                     c_flag_ = (flags >> 29) & 1;
  2629                     v_flag_ = (flags >> 28) & 1;
  2630                 } else {
  2631                     MOZ_CRASH();
  2634         } else if (instr->bits(22, 21) == 1) {
  2635             int rm = instr->rmValue();
  2636             switch (instr->bits(7, 4)) {
  2637               case 1:   // BX
  2638                 set_pc(get_register(rm));
  2639                 break;
  2640               case 3: { // BLX
  2641                 uint32_t old_pc = get_pc();
  2642                 set_pc(get_register(rm));
  2643                 set_register(lr, old_pc + SimInstruction::kInstrSize);
  2644                 break;
  2646               case 7: { // BKPT
  2647                 ArmDebugger dbg(this);
  2648                 printf("Simulator hit BKPT.\n");
  2649                 dbg.debug();
  2650                 break;
  2652               default:
  2653                 MOZ_CRASH();
  2655         } else if (instr->bits(22, 21) == 3) {
  2656             int rm = instr->rmValue();
  2657             int rd = instr->rdValue();
  2658             switch (instr->bits(7, 4)) {
  2659               case 1: { // CLZ
  2660                 uint32_t bits = get_register(rm);
  2661                 int leading_zeros = 0;
  2662                 if (bits == 0)
  2663                     leading_zeros = 32;
  2664                 else
  2665                     leading_zeros = mozilla::CountLeadingZeroes32(bits);
  2666                 set_register(rd, leading_zeros);
  2667                 break;
  2669               default:
  2670                 MOZ_CRASH();
  2671                 break;
  2673         } else {
  2674             printf("%08x\n", instr->instructionBits());
  2675             MOZ_CRASH();
  2677     } else if ((type == 1) && instr->isNopType1()) {
  2678         // NOP.
  2679     } else {
  2680         int rd = instr->rdValue();
  2681         int rn = instr->rnValue();
  2682         int32_t rn_val = get_register(rn);
  2683         int32_t shifter_operand = 0;
  2684         bool shifter_carry_out = 0;
  2685         if (type == 0) {
  2686             shifter_operand = getShiftRm(instr, &shifter_carry_out);
  2687         } else {
  2688             MOZ_ASSERT(instr->typeValue() == 1);
  2689             shifter_operand = getImm(instr, &shifter_carry_out);
  2691         int32_t alu_out;
  2692         switch (instr->opcodeField()) {
  2693           case op_and:
  2694             alu_out = rn_val & shifter_operand;
  2695             set_register(rd, alu_out);
  2696             if (instr->hasS()) {
  2697                 setNZFlags(alu_out);
  2698                 setCFlag(shifter_carry_out);
  2700             break;
  2701           case op_eor:
  2702             alu_out = rn_val ^ shifter_operand;
  2703             set_register(rd, alu_out);
  2704             if (instr->hasS()) {
  2705                 setNZFlags(alu_out);
  2706                 setCFlag(shifter_carry_out);
  2708             break;
  2709           case op_sub:
  2710             alu_out = rn_val - shifter_operand;
  2711             set_register(rd, alu_out);
  2712             if (instr->hasS()) {
  2713                 setNZFlags(alu_out);
  2714                 setCFlag(!borrowFrom(rn_val, shifter_operand));
  2715                 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
  2717             break;
  2718           case op_rsb:
  2719             alu_out = shifter_operand - rn_val;
  2720             set_register(rd, alu_out);
  2721             if (instr->hasS()) {
  2722                 setNZFlags(alu_out);
  2723                 setCFlag(!borrowFrom(shifter_operand, rn_val));
  2724                 setVFlag(overflowFrom(alu_out, shifter_operand, rn_val, false));
  2726             break;
  2727           case op_add:
  2728             alu_out = rn_val + shifter_operand;
  2729             set_register(rd, alu_out);
  2730             if (instr->hasS()) {
  2731                 setNZFlags(alu_out);
  2732                 setCFlag(carryFrom(rn_val, shifter_operand));
  2733                 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
  2735             break;
  2736           case op_adc:
  2737             alu_out = rn_val + shifter_operand + getCarry();
  2738             set_register(rd, alu_out);
  2739             if (instr->hasS()) {
  2740                 setNZFlags(alu_out);
  2741                 setCFlag(carryFrom(rn_val, shifter_operand, getCarry()));
  2742                 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
  2744             break;
  2745           case op_sbc:
  2746           case op_rsc:
  2747             MOZ_CRASH();
  2748             break;
  2749           case op_tst:
  2750             if (instr->hasS()) {
  2751                 alu_out = rn_val & shifter_operand;
  2752                 setNZFlags(alu_out);
  2753                 setCFlag(shifter_carry_out);
  2754             } else {
  2755                 alu_out = instr->immedMovwMovtValue();
  2756                 set_register(rd, alu_out);
  2758             break;
  2759           case op_teq:
  2760             if (instr->hasS()) {
  2761                 alu_out = rn_val ^ shifter_operand;
  2762                 setNZFlags(alu_out);
  2763                 setCFlag(shifter_carry_out);
  2764             } else {
  2765                 // Other instructions matching this pattern are handled in the
  2766                 // miscellaneous instructions part above.
  2767                 MOZ_CRASH();
  2769             break;
  2770           case op_cmp:
  2771             if (instr->hasS()) {
  2772                 alu_out = rn_val - shifter_operand;
  2773                 setNZFlags(alu_out);
  2774                 setCFlag(!borrowFrom(rn_val, shifter_operand));
  2775                 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
  2776             } else {
  2777                 alu_out = (get_register(rd) & 0xffff) |
  2778                     (instr->immedMovwMovtValue() << 16);
  2779                 set_register(rd, alu_out);
  2781             break;
  2782           case op_cmn:
  2783             if (instr->hasS()) {
  2784                 alu_out = rn_val + shifter_operand;
  2785                 setNZFlags(alu_out);
  2786                 setCFlag(carryFrom(rn_val, shifter_operand));
  2787                 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
  2788             } else {
  2789                 // Other instructions matching this pattern are handled in the
  2790                 // miscellaneous instructions part above.
  2791                 MOZ_CRASH();
  2793             break;
  2794           case op_orr:
  2795             alu_out = rn_val | shifter_operand;
  2796             set_register(rd, alu_out);
  2797             if (instr->hasS()) {
  2798                 setNZFlags(alu_out);
  2799                 setCFlag(shifter_carry_out);
  2801             break;
  2802           case op_mov:
  2803             alu_out = shifter_operand;
  2804             set_register(rd, alu_out);
  2805             if (instr->hasS()) {
  2806                 setNZFlags(alu_out);
  2807                 setCFlag(shifter_carry_out);
  2809             break;
  2810           case op_bic:
  2811             alu_out = rn_val & ~shifter_operand;
  2812             set_register(rd, alu_out);
  2813             if (instr->hasS()) {
  2814                 setNZFlags(alu_out);
  2815                 setCFlag(shifter_carry_out);
  2817             break;
  2818           case op_mvn:
  2819             alu_out = ~shifter_operand;
  2820             set_register(rd, alu_out);
  2821             if (instr->hasS()) {
  2822                 setNZFlags(alu_out);
  2823                 setCFlag(shifter_carry_out);
  2825             break;
  2826           default:
  2827             MOZ_CRASH();
  2828             break;
  2833 void
  2834 Simulator::decodeType2(SimInstruction *instr)
  2836     int rd = instr->rdValue();
  2837     int rn = instr->rnValue();
  2838     int32_t rn_val = get_register(rn);
  2839     int32_t im_val = instr->offset12Value();
  2840     int32_t addr = 0;
  2841     switch (instr->PUField()) {
  2842       case da_x:
  2843         MOZ_ASSERT(!instr->hasW());
  2844         addr = rn_val;
  2845         rn_val -= im_val;
  2846         set_register(rn, rn_val);
  2847         break;
  2848       case ia_x:
  2849         MOZ_ASSERT(!instr->hasW());
  2850         addr = rn_val;
  2851         rn_val += im_val;
  2852         set_register(rn, rn_val);
  2853         break;
  2854       case db_x:
  2855         rn_val -= im_val;
  2856         addr = rn_val;
  2857         if (instr->hasW())
  2858             set_register(rn, rn_val);
  2859         break;
  2860       case ib_x:
  2861         rn_val += im_val;
  2862         addr = rn_val;
  2863         if (instr->hasW())
  2864             set_register(rn, rn_val);
  2865         break;
  2866       default:
  2867         MOZ_CRASH();
  2868         break;
  2870     if (instr->hasB()) {
  2871         if (instr->hasL()) {
  2872             uint8_t val = readBU(addr);
  2873             set_register(rd, val);
  2874         } else {
  2875             uint8_t val = get_register(rd);
  2876             writeB(addr, val);
  2878     } else {
  2879         if (instr->hasL())
  2880             set_register(rd, readW(addr, instr));
  2881         else
  2882             writeW(addr, get_register(rd), instr);
  2886 void
  2887 Simulator::decodeType3(SimInstruction *instr)
  2889     int rd = instr->rdValue();
  2890     int rn = instr->rnValue();
  2891     int32_t rn_val = get_register(rn);
  2892     bool shifter_carry_out = 0;
  2893     int32_t shifter_operand = getShiftRm(instr, &shifter_carry_out);
  2894     int32_t addr = 0;
  2895     switch (instr->PUField()) {
  2896       case da_x:
  2897         MOZ_ASSERT(!instr->hasW());
  2898         MOZ_CRASH();
  2899         break;
  2900       case ia_x: {
  2901         if (instr->bit(4) == 0) {
  2902             // Memop.
  2903         } else {
  2904             if (instr->bit(5) == 0) {
  2905                 switch (instr->bits(22, 21)) {
  2906                   case 0:
  2907                     if (instr->bit(20) == 0) {
  2908                         if (instr->bit(6) == 0) {
  2909                             // Pkhbt.
  2910                             uint32_t rn_val = get_register(rn);
  2911                             uint32_t rm_val = get_register(instr->rmValue());
  2912                             int32_t shift = instr->bits(11, 7);
  2913                             rm_val <<= shift;
  2914                             set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
  2915                         } else {
  2916                             // Pkhtb.
  2917                             uint32_t rn_val = get_register(rn);
  2918                             int32_t rm_val = get_register(instr->rmValue());
  2919                             int32_t shift = instr->bits(11, 7);
  2920                             if (shift == 0)
  2921                                 shift = 32;
  2922                             rm_val >>= shift;
  2923                             set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
  2925                     } else {
  2926                         MOZ_CRASH();
  2928                     break;
  2929                   case 1:
  2930                     MOZ_CRASH();
  2931                     break;
  2932                   case 2:
  2933                     MOZ_CRASH();
  2934                     break;
  2935                   case 3: {
  2936                     // Usat.
  2937                       int32_t sat_pos = instr->bits(20, 16);
  2938                       int32_t sat_val = (1 << sat_pos) - 1;
  2939                       int32_t shift = instr->bits(11, 7);
  2940                       int32_t shift_type = instr->bit(6);
  2941                       int32_t rm_val = get_register(instr->rmValue());
  2942                       if (shift_type == 0) // LSL
  2943                           rm_val <<= shift;
  2944                       else // ASR
  2945                           rm_val >>= shift;
  2947                       // If saturation occurs, the Q flag should be set in the CPSR.
  2948                       // There is no Q flag yet, and no instruction (MRS) to read the
  2949                       // CPSR directly.
  2950                       if (rm_val > sat_val)
  2951                           rm_val = sat_val;
  2952                       else if (rm_val < 0)
  2953                           rm_val = 0;
  2954                       set_register(rd, rm_val);
  2955                       break;
  2958             } else {
  2959                 switch (instr->bits(22, 21)) {
  2960                   case 0:
  2961                     MOZ_CRASH();
  2962                     break;
  2963                   case 1:
  2964                     MOZ_CRASH();
  2965                     break;
  2966                   case 2:
  2967                     if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
  2968                         if (instr->bits(19, 16) == 0xF) {
  2969                             // Uxtb16.
  2970                             uint32_t rm_val = get_register(instr->rmValue());
  2971                             int32_t rotate = instr->bits(11, 10);
  2972                             switch (rotate) {
  2973                               case 0:
  2974                                 break;
  2975                               case 1:
  2976                                 rm_val = (rm_val >> 8) | (rm_val << 24);
  2977                                 break;
  2978                               case 2:
  2979                                 rm_val = (rm_val >> 16) | (rm_val << 16);
  2980                                 break;
  2981                               case 3:
  2982                                 rm_val = (rm_val >> 24) | (rm_val << 8);
  2983                                 break;
  2985                             set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
  2986                         } else {
  2987                             MOZ_CRASH();
  2989                     } else {
  2990                         MOZ_CRASH();
  2992                     break;
  2993                   case 3:
  2994                     if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
  2995                         if (instr->bits(19, 16) == 0xF) {
  2996                             // Uxtb.
  2997                             uint32_t rm_val = get_register(instr->rmValue());
  2998                             int32_t rotate = instr->bits(11, 10);
  2999                             switch (rotate) {
  3000                               case 0:
  3001                                 break;
  3002                               case 1:
  3003                                 rm_val = (rm_val >> 8) | (rm_val << 24);
  3004                                 break;
  3005                               case 2:
  3006                                 rm_val = (rm_val >> 16) | (rm_val << 16);
  3007                                 break;
  3008                               case 3:
  3009                                 rm_val = (rm_val >> 24) | (rm_val << 8);
  3010                                 break;
  3012                             set_register(rd, (rm_val & 0xFF));
  3013                         } else {
  3014                             // Uxtab.
  3015                             uint32_t rn_val = get_register(rn);
  3016                             uint32_t rm_val = get_register(instr->rmValue());
  3017                             int32_t rotate = instr->bits(11, 10);
  3018                             switch (rotate) {
  3019                               case 0:
  3020                                   break;
  3021                               case 1:
  3022                                 rm_val = (rm_val >> 8) | (rm_val << 24);
  3023                                 break;
  3024                               case 2:
  3025                                 rm_val = (rm_val >> 16) | (rm_val << 16);
  3026                                 break;
  3027                               case 3:
  3028                                 rm_val = (rm_val >> 24) | (rm_val << 8);
  3029                                 break;
  3031                             set_register(rd, rn_val + (rm_val & 0xFF));
  3033                     } else {
  3034                         MOZ_CRASH();
  3036                     break;
  3039             return;
  3041         break;
  3043       case db_x: { // sudiv
  3044         if (instr->bit(22) == 0x0 && instr->bit(20) == 0x1 &&
  3045             instr->bits(15,12) == 0x0f && instr->bits(7, 4) == 0x1) {
  3046             if (!instr->hasW()) {
  3047                 // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs
  3048                 int rm = instr->rmValue();
  3049                 int32_t rm_val = get_register(rm);
  3050                 int rs = instr->rsValue();
  3051                 int32_t rs_val = get_register(rs);
  3052                 int32_t ret_val = 0;
  3053                 MOZ_ASSERT(rs_val != 0);
  3054                 if ((rm_val == INT32_MIN) && (rs_val == -1))
  3055                     ret_val = INT32_MIN;
  3056                 else
  3057                     ret_val = rm_val / rs_val;
  3058                 set_register(rn, ret_val);
  3059                 return;
  3060             } else {
  3061                 // udiv (in V8 notation matching ARM ISA format) rn = rm/rs
  3062                 int rm = instr->rmValue();
  3063                 uint32_t rm_val = get_register(rm);
  3064                 int rs = instr->rsValue();
  3065                 uint32_t rs_val = get_register(rs);
  3066                 uint32_t ret_val = 0;
  3067                 MOZ_ASSERT(rs_val != 0);
  3068                 ret_val = rm_val / rs_val;
  3069                 set_register(rn, ret_val);
  3070                 return;
  3074         addr = rn_val - shifter_operand;
  3075         if (instr->hasW())
  3076             set_register(rn, addr);
  3077         break;
  3079       case ib_x: {
  3080         if (instr->hasW() && (instr->bits(6, 4) == 0x5)) {
  3081             uint32_t widthminus1 = static_cast<uint32_t>(instr->bits(20, 16));
  3082             uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
  3083             uint32_t msbit = widthminus1 + lsbit;
  3084             if (msbit <= 31) {
  3085                 if (instr->bit(22)) {
  3086                     // ubfx - unsigned bitfield extract.
  3087                     uint32_t rm_val = static_cast<uint32_t>(get_register(instr->rmValue()));
  3088                     uint32_t extr_val = rm_val << (31 - msbit);
  3089                     extr_val = extr_val >> (31 - widthminus1);
  3090                     set_register(instr->rdValue(), extr_val);
  3091                 } else {
  3092                     // sbfx - signed bitfield extract.
  3093                     int32_t rm_val = get_register(instr->rmValue());
  3094                     int32_t extr_val = rm_val << (31 - msbit);
  3095                     extr_val = extr_val >> (31 - widthminus1);
  3096                     set_register(instr->rdValue(), extr_val);
  3098             } else {
  3099                 MOZ_CRASH();
  3101             return;
  3102         } else if (!instr->hasW() && (instr->bits(6, 4) == 0x1)) {
  3103             uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
  3104             uint32_t msbit = static_cast<uint32_t>(instr->bits(20, 16));
  3105             if (msbit >= lsbit) {
  3106                 // bfc or bfi - bitfield clear/insert.
  3107                 uint32_t rd_val =
  3108                     static_cast<uint32_t>(get_register(instr->rdValue()));
  3109                 uint32_t bitcount = msbit - lsbit + 1;
  3110                 uint32_t mask = (1 << bitcount) - 1;
  3111                 rd_val &= ~(mask << lsbit);
  3112                 if (instr->rmValue() != 15) {
  3113                     // bfi - bitfield insert.
  3114                     uint32_t rm_val =
  3115                         static_cast<uint32_t>(get_register(instr->rmValue()));
  3116                     rm_val &= mask;
  3117                     rd_val |= rm_val << lsbit;
  3119                 set_register(instr->rdValue(), rd_val);
  3120             } else {
  3121                 MOZ_CRASH();
  3123             return;
  3124         } else {
  3125             addr = rn_val + shifter_operand;
  3126             if (instr->hasW())
  3127                 set_register(rn, addr);
  3129         break;
  3131       default:
  3132         MOZ_CRASH();
  3133         break;
  3135     if (instr->hasB()) {
  3136         if (instr->hasL()) {
  3137             uint8_t byte = readB(addr);
  3138             set_register(rd, byte);
  3139         } else {
  3140             uint8_t byte = get_register(rd);
  3141             writeB(addr, byte);
  3143     } else {
  3144         if (instr->hasL())
  3145             set_register(rd, readW(addr, instr));
  3146         else
  3147             writeW(addr, get_register(rd), instr);
  3151 void
  3152 Simulator::decodeType4(SimInstruction *instr)
  3154     MOZ_ASSERT(instr->bit(22) == 0); // Only allowed to be set in privileged mode.
  3155     bool load = instr->hasL();
  3156     handleRList(instr, load);
  3159 void
  3160 Simulator::decodeType5(SimInstruction *instr)
  3162     int off = instr->sImmed24Value() << 2;
  3163     intptr_t pc_address = get_pc();
  3164     if (instr->hasLink())
  3165         set_register(lr, pc_address + SimInstruction::kInstrSize);
  3166     int pc_reg = get_register(pc);
  3167     set_pc(pc_reg + off);
  3170 void
  3171 Simulator::decodeType6(SimInstruction *instr)
  3173     decodeType6CoprocessorIns(instr);
  3176 void
  3177 Simulator::decodeType7(SimInstruction *instr)
  3179     if (instr->bit(24) == 1)
  3180         softwareInterrupt(instr);
  3181     else
  3182         decodeTypeVFP(instr);
  3185 void
  3186 Simulator::decodeTypeVFP(SimInstruction *instr)
  3188     MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0);
  3189     MOZ_ASSERT(instr->bits(11, 9) == 0x5);
  3191     // Obtain double precision register codes.
  3192     VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
  3193     int vm = instr->VFPMRegValue(precision);
  3194     int vd = instr->VFPDRegValue(precision);
  3195     int vn = instr->VFPNRegValue(precision);
  3197     if (instr->bit(4) == 0) {
  3198         if (instr->opc1Value() == 0x7) {
  3199             // Other data processing instructions
  3200             if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x1)) {
  3201                 // vmov register to register.
  3202                 if (instr->szValue() == 0x1) {
  3203                     int m = instr->VFPMRegValue(kDoublePrecision);
  3204                     int d = instr->VFPDRegValue(kDoublePrecision);
  3205                     set_d_register_from_double(d, get_double_from_d_register(m));
  3206                 } else {
  3207                     int m = instr->VFPMRegValue(kSinglePrecision);
  3208                     int d = instr->VFPDRegValue(kSinglePrecision);
  3209                     set_s_register_from_float(d, get_float_from_s_register(m));
  3211             } else if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x3)) {
  3212                 // vabs
  3213                 if (instr->szValue() == 0x1) {
  3214                     double dm_value = get_double_from_d_register(vm);
  3215                     double dd_value = std::fabs(dm_value);
  3216                     dd_value = canonicalizeNaN(dd_value);
  3217                     set_d_register_from_double(vd, dd_value);
  3218                 } else {
  3219                     float fm_value = get_float_from_s_register(vm);
  3220                     float fd_value = std::fabs(fm_value);
  3221                     fd_value = canonicalizeNaN(fd_value);
  3222                     set_s_register_from_float(vd, fd_value);
  3224             } else if ((instr->opc2Value() == 0x1) && (instr->opc3Value() == 0x1)) {
  3225                 // vneg
  3226                 if (instr->szValue() == 0x1) {
  3227                     double dm_value = get_double_from_d_register(vm);
  3228                     double dd_value = -dm_value;
  3229                     dd_value = canonicalizeNaN(dd_value);
  3230                     set_d_register_from_double(vd, dd_value);
  3231                 } else {
  3232                     float fm_value = get_float_from_s_register(vm);
  3233                     float fd_value = -fm_value;
  3234                     fd_value = canonicalizeNaN(fd_value);
  3235                     set_s_register_from_float(vd, fd_value);
  3237             } else if ((instr->opc2Value() == 0x7) && (instr->opc3Value() == 0x3)) {
  3238                 decodeVCVTBetweenDoubleAndSingle(instr);
  3239             } else if ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) {
  3240                 decodeVCVTBetweenFloatingPointAndInteger(instr);
  3241             } else if ((instr->opc2Value() == 0xA) && (instr->opc3Value() == 0x3) &&
  3242                        (instr->bit(8) == 1)) {
  3243                 // vcvt.f64.s32 Dd, Dd, #<fbits>
  3244                 int fraction_bits = 32 - ((instr->bits(3, 0) << 1) | instr->bit(5));
  3245                 int fixed_value = get_sinteger_from_s_register(vd * 2);
  3246                 double divide = 1 << fraction_bits;
  3247                 set_d_register_from_double(vd, fixed_value / divide);
  3248             } else if (((instr->opc2Value() >> 1) == 0x6) &&
  3249                        (instr->opc3Value() & 0x1)) {
  3250                 decodeVCVTBetweenFloatingPointAndInteger(instr);
  3251             } else if (((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
  3252                        (instr->opc3Value() & 0x1)) {
  3253                 decodeVCMP(instr);
  3254             } else if (((instr->opc2Value() == 0x1)) && (instr->opc3Value() == 0x3)) {
  3255                 // vsqrt
  3256                 if (instr->szValue() == 0x1) {
  3257                     double dm_value = get_double_from_d_register(vm);
  3258                     double dd_value = std::sqrt(dm_value);
  3259                     dd_value = canonicalizeNaN(dd_value);
  3260                     set_d_register_from_double(vd, dd_value);
  3261                 } else {
  3262                     float fm_value = get_float_from_s_register(vm);
  3263                     float fd_value = std::sqrt(fm_value);
  3264                     fd_value = canonicalizeNaN(fd_value);
  3265                     set_s_register_from_float(vd, fd_value);
  3267             } else if (instr->opc3Value() == 0x0) {
  3268                 // vmov immediate.
  3269                 if (instr->szValue() == 0x1) {
  3270                     set_d_register_from_double(vd, instr->doubleImmedVmov());
  3271                 } else {
  3272                     // vmov.f32 immediate
  3273                     set_s_register_from_float(vd, instr->float32ImmedVmov());
  3275             } else {
  3276                 decodeVCVTBetweenFloatingPointAndIntegerFrac(instr);
  3278         } else if (instr->opc1Value() == 0x3) {
  3279             if (instr->szValue() != 0x1) {
  3280                 if (instr->opc3Value() & 0x1) {
  3281                     // vsub
  3282                     float fn_value = get_float_from_s_register(vn);
  3283                     float fm_value = get_float_from_s_register(vm);
  3284                     float fd_value = fn_value - fm_value;
  3285                     fd_value = canonicalizeNaN(fd_value);
  3286                     set_s_register_from_float(vd, fd_value);
  3287                 } else {
  3288                     // vadd
  3289                     float fn_value = get_float_from_s_register(vn);
  3290                     float fm_value = get_float_from_s_register(vm);
  3291                     float fd_value = fn_value + fm_value;
  3292                     fd_value = canonicalizeNaN(fd_value);
  3293                     set_s_register_from_float(vd, fd_value);
  3295             } else {
  3296                 if (instr->opc3Value() & 0x1) {
  3297                     // vsub
  3298                     double dn_value = get_double_from_d_register(vn);
  3299                     double dm_value = get_double_from_d_register(vm);
  3300                     double dd_value = dn_value - dm_value;
  3301                     dd_value = canonicalizeNaN(dd_value);
  3302                     set_d_register_from_double(vd, dd_value);
  3303                 } else {
  3304                     // vadd
  3305                     double dn_value = get_double_from_d_register(vn);
  3306                     double dm_value = get_double_from_d_register(vm);
  3307                     double dd_value = dn_value + dm_value;
  3308                     dd_value = canonicalizeNaN(dd_value);
  3309                     set_d_register_from_double(vd, dd_value);
  3312         } else if ((instr->opc1Value() == 0x2) && !(instr->opc3Value() & 0x1)) {
  3313             // vmul
  3314             if (instr->szValue() != 0x1) {
  3315                 float fn_value = get_float_from_s_register(vn);
  3316                 float fm_value = get_float_from_s_register(vm);
  3317                 float fd_value = fn_value * fm_value;
  3318                 fd_value = canonicalizeNaN(fd_value);
  3319                 set_s_register_from_float(vd, fd_value);
  3320             } else {
  3321                 double dn_value = get_double_from_d_register(vn);
  3322                 double dm_value = get_double_from_d_register(vm);
  3323                 double dd_value = dn_value * dm_value;
  3324                 dd_value = canonicalizeNaN(dd_value);
  3325                 set_d_register_from_double(vd, dd_value);
  3327         } else if ((instr->opc1Value() == 0x0)) {
  3328             // vmla, vmls
  3329             const bool is_vmls = (instr->opc3Value() & 0x1);
  3331             if (instr->szValue() != 0x1)
  3332                 MOZ_ASSUME_UNREACHABLE();  // Not used by V8.
  3334             const double dd_val = get_double_from_d_register(vd);
  3335             const double dn_val = get_double_from_d_register(vn);
  3336             const double dm_val = get_double_from_d_register(vm);
  3338             // Note: we do the mul and add/sub in separate steps to avoid getting a
  3339             // result with too high precision.
  3340             set_d_register_from_double(vd, dn_val * dm_val);
  3341             if (is_vmls) {
  3342                 set_d_register_from_double(vd,
  3343                                            canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
  3344             } else {
  3345                 set_d_register_from_double(vd,
  3346                                            canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
  3348         } else if ((instr->opc1Value() == 0x4) && !(instr->opc3Value() & 0x1)) {
  3349             // vdiv
  3350             if (instr->szValue() != 0x1) {
  3351                 float fn_value = get_float_from_s_register(vn);
  3352                 float fm_value = get_float_from_s_register(vm);
  3353                 float fd_value = fn_value / fm_value;
  3354                 div_zero_vfp_flag_ = (fm_value == 0);
  3355                 fd_value = canonicalizeNaN(fd_value);
  3356                 set_s_register_from_float(vd, fd_value);
  3357             } else {
  3358                 double dn_value = get_double_from_d_register(vn);
  3359                 double dm_value = get_double_from_d_register(vm);
  3360                 double dd_value = dn_value / dm_value;
  3361                 div_zero_vfp_flag_ = (dm_value == 0);
  3362                 dd_value = canonicalizeNaN(dd_value);
  3363                 set_d_register_from_double(vd, dd_value);
  3365         } else {
  3366             MOZ_CRASH();
  3368     } else {
  3369         if (instr->VCValue() == 0x0 && instr->VAValue() == 0x0) {
  3370             decodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
  3371         } else if ((instr->VLValue() == 0x0) &&
  3372                    (instr->VCValue() == 0x1) &&
  3373                    (instr->bit(23) == 0x0)) {
  3374             // vmov (ARM core register to scalar)
  3375             int vd = instr->bits(19, 16) | (instr->bit(7) << 4);
  3376             double dd_value = get_double_from_d_register(vd);
  3377             int32_t data[2];
  3378             memcpy(data, &dd_value, 8);
  3379             data[instr->bit(21)] = get_register(instr->rtValue());
  3380             memcpy(&dd_value, data, 8);
  3381             set_d_register_from_double(vd, dd_value);
  3382         } else if ((instr->VLValue() == 0x1) &&
  3383                    (instr->VCValue() == 0x1) &&
  3384                    (instr->bit(23) == 0x0)) {
  3385             // vmov (scalar to ARM core register)
  3386             int vn = instr->bits(19, 16) | (instr->bit(7) << 4);
  3387             double dn_value = get_double_from_d_register(vn);
  3388             int32_t data[2];
  3389             memcpy(data, &dn_value, 8);
  3390             set_register(instr->rtValue(), data[instr->bit(21)]);
  3391         } else if ((instr->VLValue() == 0x1) &&
  3392                    (instr->VCValue() == 0x0) &&
  3393                    (instr->VAValue() == 0x7) &&
  3394                    (instr->bits(19, 16) == 0x1)) {
  3395             // vmrs
  3396             uint32_t rt = instr->rtValue();
  3397             if (rt == 0xF) {
  3398                 copy_FPSCR_to_APSR();
  3399             } else {
  3400                 // Emulate FPSCR from the Simulator flags.
  3401                 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
  3402                     (z_flag_FPSCR_ << 30) |
  3403                     (c_flag_FPSCR_ << 29) |
  3404                     (v_flag_FPSCR_ << 28) |
  3405                     (FPSCR_default_NaN_mode_ << 25) |
  3406                     (inexact_vfp_flag_ << 4) |
  3407                     (underflow_vfp_flag_ << 3) |
  3408                     (overflow_vfp_flag_ << 2) |
  3409                     (div_zero_vfp_flag_ << 1) |
  3410                     (inv_op_vfp_flag_ << 0) |
  3411                     (FPSCR_rounding_mode_);
  3412                 set_register(rt, fpscr);
  3414         } else if ((instr->VLValue() == 0x0) &&
  3415                    (instr->VCValue() == 0x0) &&
  3416                    (instr->VAValue() == 0x7) &&
  3417                    (instr->bits(19, 16) == 0x1)) {
  3418             // vmsr
  3419             uint32_t rt = instr->rtValue();
  3420             if (rt == pc) {
  3421                 MOZ_CRASH();
  3422             } else {
  3423                 uint32_t rt_value = get_register(rt);
  3424                 n_flag_FPSCR_ = (rt_value >> 31) & 1;
  3425                 z_flag_FPSCR_ = (rt_value >> 30) & 1;
  3426                 c_flag_FPSCR_ = (rt_value >> 29) & 1;
  3427                 v_flag_FPSCR_ = (rt_value >> 28) & 1;
  3428                 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
  3429                 inexact_vfp_flag_ = (rt_value >> 4) & 1;
  3430                 underflow_vfp_flag_ = (rt_value >> 3) & 1;
  3431                 overflow_vfp_flag_ = (rt_value >> 2) & 1;
  3432                 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
  3433                 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
  3434                 FPSCR_rounding_mode_ =
  3435                     static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
  3437         } else {
  3438             MOZ_CRASH();
  3443 void
  3444 Simulator::decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr)
  3446     MOZ_ASSERT(instr->bit(4) == 1 &&
  3447                instr->VCValue() == 0x0 &&
  3448                instr->VAValue() == 0x0);
  3450     int t = instr->rtValue();
  3451     int n = instr->VFPNRegValue(kSinglePrecision);
  3452     bool to_arm_register = (instr->VLValue() == 0x1);
  3453     if (to_arm_register) {
  3454         int32_t int_value = get_sinteger_from_s_register(n);
  3455         set_register(t, int_value);
  3456     } else {
  3457         int32_t rs_val = get_register(t);
  3458         set_s_register_from_sinteger(n, rs_val);
  3462 void
  3463 Simulator::decodeVCMP(SimInstruction *instr)
  3465     MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7));
  3466     MOZ_ASSERT(((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
  3467                (instr->opc3Value() & 0x1));
  3468     // Comparison.
  3470     VFPRegPrecision precision = kSinglePrecision;
  3471     if (instr->szValue() == 1)
  3472         precision = kDoublePrecision;
  3474     int d = instr->VFPDRegValue(precision);
  3475     int m = 0;
  3476     if (instr->opc2Value() == 0x4)
  3477         m = instr->VFPMRegValue(precision);
  3479     if (precision == kDoublePrecision) {
  3480         double dd_value = get_double_from_d_register(d);
  3481         double dm_value = 0.0;
  3482         if (instr->opc2Value() == 0x4) {
  3483             dm_value = get_double_from_d_register(m);
  3486         // Raise exceptions for quiet NaNs if necessary.
  3487         if (instr->bit(7) == 1) {
  3488             if (mozilla::IsNaN(dd_value))
  3489                 inv_op_vfp_flag_ = true;
  3491         compute_FPSCR_Flags(dd_value, dm_value);
  3492     } else {
  3493         float fd_value = get_float_from_s_register(d);
  3494         float fm_value = 0.0;
  3495         if (instr->opc2Value() == 0x4)
  3496             fm_value = get_float_from_s_register(m);
  3498         // Raise exceptions for quiet NaNs if necessary.
  3499         if (instr->bit(7) == 1) {
  3500             if (mozilla::IsNaN(fd_value))
  3501                 inv_op_vfp_flag_ = true;
  3503         compute_FPSCR_Flags(fd_value, fm_value);
  3507 void
  3508 Simulator::decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr)
  3510     MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7);
  3511     MOZ_ASSERT(instr->opc2Value() == 0x7 && instr->opc3Value() == 0x3);
  3513     VFPRegPrecision dst_precision = kDoublePrecision;
  3514     VFPRegPrecision src_precision = kSinglePrecision;
  3515     if (instr->szValue() == 1) {
  3516         dst_precision = kSinglePrecision;
  3517         src_precision = kDoublePrecision;
  3520     int dst = instr->VFPDRegValue(dst_precision);
  3521     int src = instr->VFPMRegValue(src_precision);
  3523     if (dst_precision == kSinglePrecision) {
  3524         double val = get_double_from_d_register(src);
  3525         set_s_register_from_float(dst, static_cast<float>(val));
  3526     } else {
  3527         float val = get_float_from_s_register(src);
  3528         set_d_register_from_double(dst, static_cast<double>(val));
  3532 static bool
  3533 get_inv_op_vfp_flag(VFPRoundingMode mode, double val, bool unsigned_)
  3535     MOZ_ASSERT(mode == SimRN || mode == SimRM || mode == SimRZ);
  3536     double max_uint = static_cast<double>(0xffffffffu);
  3537     double max_int = static_cast<double>(INT32_MAX);
  3538     double min_int = static_cast<double>(INT32_MIN);
  3540     // Check for NaN.
  3541     if (val != val)
  3542         return true;
  3544     // Check for overflow. This code works because 32bit integers can be
  3545     // exactly represented by ieee-754 64bit floating-point values.
  3546     switch (mode) {
  3547       case SimRN:
  3548         return  unsigned_ ? (val >= (max_uint + 0.5)) ||
  3549                             (val < -0.5)
  3550                           : (val >= (max_int + 0.5)) ||
  3551                             (val < (min_int - 0.5));
  3552       case SimRM:
  3553         return  unsigned_ ? (val >= (max_uint + 1.0)) ||
  3554                             (val < 0)
  3555                           : (val >= (max_int + 1.0)) ||
  3556                             (val < min_int);
  3557       case SimRZ:
  3558         return  unsigned_ ? (val >= (max_uint + 1.0)) ||
  3559                             (val <= -1)
  3560                           : (val >= (max_int + 1.0)) ||
  3561                             (val <= (min_int - 1.0));
  3562       default:
  3563         MOZ_CRASH();
  3564         return true;
  3568 // We call this function only if we had a vfp invalid exception.
  3569 // It returns the correct saturated value.
  3570 static int
  3571 VFPConversionSaturate(double val, bool unsigned_res)
  3573     if (val != val) // NaN.
  3574         return 0;
  3575     if (unsigned_res)
  3576         return (val < 0) ? 0 : 0xffffffffu;
  3577     return (val < 0) ? INT32_MIN : INT32_MAX;
  3580 void
  3581 Simulator::decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr)
  3583     MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7) &&
  3584                (instr->bits(27, 23) == 0x1D));
  3585     MOZ_ASSERT(((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) ||
  3586                (((instr->opc2Value() >> 1) == 0x6) && (instr->opc3Value() & 0x1)));
  3588     // Conversion between floating-point and integer.
  3589     bool to_integer = (instr->bit(18) == 1);
  3591     VFPRegPrecision src_precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
  3593     if (to_integer) {
  3594         // We are playing with code close to the C++ standard's limits below,
  3595         // hence the very simple code and heavy checks.
  3596         //
  3597         // Note:
  3598         // C++ defines default type casting from floating point to integer as
  3599         // (close to) rounding toward zero ("fractional part discarded").
  3601         int dst = instr->VFPDRegValue(kSinglePrecision);
  3602         int src = instr->VFPMRegValue(src_precision);
  3604         // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
  3605         // mode or the default Round to Zero mode.
  3606         VFPRoundingMode mode = (instr->bit(7) != 1) ? FPSCR_rounding_mode_ : SimRZ;
  3607         MOZ_ASSERT(mode == SimRM || mode == SimRZ || mode == SimRN);
  3609         bool unsigned_integer = (instr->bit(16) == 0);
  3610         bool double_precision = (src_precision == kDoublePrecision);
  3612         double val = double_precision
  3613                      ? get_double_from_d_register(src)
  3614                      : get_float_from_s_register(src);
  3616         int temp = unsigned_integer ? static_cast<uint32_t>(val) : static_cast<int32_t>(val);
  3618         inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
  3620         double abs_diff = unsigned_integer
  3621                           ? std::fabs(val - static_cast<uint32_t>(temp))
  3622                           : std::fabs(val - temp);
  3624         inexact_vfp_flag_ = (abs_diff != 0);
  3626         if (inv_op_vfp_flag_) {
  3627             temp = VFPConversionSaturate(val, unsigned_integer);
  3628         } else {
  3629             switch (mode) {
  3630               case SimRN: {
  3631                 int val_sign = (val > 0) ? 1 : -1;
  3632                 if (abs_diff > 0.5) {
  3633                     temp += val_sign;
  3634                 } else if (abs_diff == 0.5) {
  3635                     // Round to even if exactly halfway.
  3636                     temp = ((temp % 2) == 0) ? temp : temp + val_sign;
  3638                 break;
  3641               case SimRM:
  3642                 temp = temp > val ? temp - 1 : temp;
  3643                   break;
  3645               case SimRZ:
  3646                 // Nothing to do.
  3647                 break;
  3649               default:
  3650                 MOZ_CRASH();
  3654         // Update the destination register.
  3655         set_s_register_from_sinteger(dst, temp);
  3656     } else {
  3657         bool unsigned_integer = (instr->bit(7) == 0);
  3658         int dst = instr->VFPDRegValue(src_precision);
  3659         int src = instr->VFPMRegValue(kSinglePrecision);
  3661         int val = get_sinteger_from_s_register(src);
  3663         if (src_precision == kDoublePrecision) {
  3664             if (unsigned_integer)
  3665                 set_d_register_from_double(dst, static_cast<double>(static_cast<uint32_t>(val)));
  3666             else
  3667                 set_d_register_from_double(dst, static_cast<double>(val));
  3668         } else {
  3669             if (unsigned_integer)
  3670                 set_s_register_from_float(dst, static_cast<float>(static_cast<uint32_t>(val)));
  3671             else
  3672                 set_s_register_from_float(dst, static_cast<float>(val));
  3677 // A VFPv3 specific instruction.
  3678 void
  3679 Simulator::decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr)
  3681     MOZ_ASSERT(instr->bits(27, 24) == 0xE && instr->opc1Value() == 0x7 && instr->bit(19) == 1 &&
  3682                instr->bit(17) == 1 && instr->bits(11,9) == 0x5 && instr->bit(6) == 1 &&
  3683                instr->bit(4) == 0);
  3685     int size = (instr->bit(7) == 1) ? 32 : 16;
  3687     int fraction_bits = size - ((instr->bits(3, 0) << 1) | instr->bit(5));
  3688     double mult = 1 << fraction_bits;
  3690     MOZ_ASSERT(size == 32); // Only handling size == 32 for now.
  3692     // Conversion between floating-point and integer.
  3693     bool to_fixed = (instr->bit(18) == 1);
  3695     VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
  3697     if (to_fixed) {
  3698         // We are playing with code close to the C++ standard's limits below,
  3699         // hence the very simple code and heavy checks.
  3700         //
  3701         // Note: C++ defines default type casting from floating point to integer as
  3702         // (close to) rounding toward zero ("fractional part discarded").
  3704         int dst = instr->VFPDRegValue(precision);
  3706         bool unsigned_integer = (instr->bit(16) == 1);
  3707         bool double_precision = (precision == kDoublePrecision);
  3709         double val = double_precision
  3710                      ? get_double_from_d_register(dst)
  3711                      : get_float_from_s_register(dst);
  3713         // Scale value by specified number of fraction bits.
  3714         val *= mult;
  3716         // Rounding down towards zero.  No need to account for the rounding error as this
  3717         // instruction always rounds down towards zero.  See SimRZ below.
  3718         int temp = unsigned_integer ? static_cast<uint32_t>(val) : static_cast<int32_t>(val);
  3720         inv_op_vfp_flag_ = get_inv_op_vfp_flag(SimRZ, val, unsigned_integer);
  3722         double abs_diff = unsigned_integer
  3723                           ? std::fabs(val - static_cast<uint32_t>(temp))
  3724                           : std::fabs(val - temp);
  3726         inexact_vfp_flag_ = (abs_diff != 0);
  3728         if (inv_op_vfp_flag_)
  3729             temp = VFPConversionSaturate(val, unsigned_integer);
  3731         // Update the destination register.
  3732         if (double_precision) {
  3733             uint32_t dbl[2];
  3734             dbl[0] = temp; dbl[1] = 0;
  3735             set_d_register(dst, dbl);
  3736         } else {
  3737             set_s_register_from_sinteger(dst, temp);
  3739     } else {
  3740         MOZ_ASSUME_UNREACHABLE();  // Not implemented, fixed to float.
  3744 void
  3745 Simulator::decodeType6CoprocessorIns(SimInstruction *instr)
  3747     MOZ_ASSERT(instr->typeValue() == 6);
  3749     if (instr->coprocessorValue() == 0xA) {
  3750         switch (instr->opcodeValue()) {
  3751           case 0x8:
  3752           case 0xA:
  3753           case 0xC:
  3754           case 0xE: {  // Load and store single precision float to memory.
  3755             int rn = instr->rnValue();
  3756             int vd = instr->VFPDRegValue(kSinglePrecision);
  3757             int offset = instr->immed8Value();
  3758             if (!instr->hasU())
  3759                 offset = -offset;
  3761             int32_t address = get_register(rn) + 4 * offset;
  3762             if (instr->hasL()) {
  3763                 // Load double from memory: vldr.
  3764                 set_s_register_from_sinteger(vd, readW(address, instr));
  3765             } else {
  3766                 // Store double to memory: vstr.
  3767                 writeW(address, get_sinteger_from_s_register(vd), instr);
  3769             break;
  3771           case 0x4:
  3772           case 0x5:
  3773           case 0x6:
  3774           case 0x7:
  3775           case 0x9:
  3776           case 0xB:
  3777             // Load/store multiple single from memory: vldm/vstm.
  3778             handleVList(instr);
  3779             break;
  3780           default:
  3781             MOZ_CRASH();
  3783     } else if (instr->coprocessorValue() == 0xB) {
  3784         switch (instr->opcodeValue()) {
  3785           case 0x2:
  3786             // Load and store double to two GP registers
  3787             if (instr->bits(7, 6) != 0 || instr->bit(4) != 1) {
  3788                 MOZ_CRASH();  // Not used atm.
  3789             } else {
  3790                 int rt = instr->rtValue();
  3791                 int rn = instr->rnValue();
  3792                 int vm = instr->VFPMRegValue(kDoublePrecision);
  3793                 if (instr->hasL()) {
  3794                     int32_t data[2];
  3795                     double d = get_double_from_d_register(vm);
  3796                     memcpy(data, &d, 8);
  3797                     set_register(rt, data[0]);
  3798                     set_register(rn, data[1]);
  3799                 } else {
  3800                     int32_t data[] = { get_register(rt), get_register(rn) };
  3801                     double d;
  3802                     memcpy(&d, data, 8);
  3803                     set_d_register_from_double(vm, d);
  3806             break;
  3807           case 0x8:
  3808           case 0xA:
  3809           case 0xC:
  3810           case 0xE: {  // Load and store double to memory.
  3811             int rn = instr->rnValue();
  3812             int vd = instr->VFPDRegValue(kDoublePrecision);
  3813             int offset = instr->immed8Value();
  3814             if (!instr->hasU())
  3815                 offset = -offset;
  3816             int32_t address = get_register(rn) + 4 * offset;
  3817             if (instr->hasL()) {
  3818                 // Load double from memory: vldr.
  3819                 int32_t data[] = {
  3820                     readW(address, instr),
  3821                     readW(address + 4, instr)
  3822                 };
  3823                 double val;
  3824                 memcpy(&val, data, 8);
  3825                 set_d_register_from_double(vd, val);
  3826             } else {
  3827                 // Store double to memory: vstr.
  3828                 int32_t data[2];
  3829                 double val = get_double_from_d_register(vd);
  3830                 memcpy(data, &val, 8);
  3831                 writeW(address, data[0], instr);
  3832                 writeW(address + 4, data[1], instr);
  3834             break;
  3836           case 0x4:
  3837           case 0x5:
  3838           case 0x6:
  3839           case 0x7:
  3840           case 0x9:
  3841           case 0xB:
  3842             // Load/store multiple double from memory: vldm/vstm.
  3843             handleVList(instr);
  3844             break;
  3845           default:
  3846             MOZ_CRASH();
  3848     } else {
  3849         MOZ_CRASH();
  3853 void
  3854 Simulator::decodeSpecialCondition(SimInstruction *instr)
  3856     switch (instr->specialValue()) {
  3857       case 5:
  3858         if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && instr->bit(4) == 1) {
  3859             // vmovl signed
  3860             int Vd = (instr->bit(22) << 4) | instr->vdValue();
  3861             int Vm = (instr->bit(5) << 4) | instr->vmValue();
  3862             int imm3 = instr->bits(21, 19);
  3863             if (imm3 != 1 && imm3 != 2 && imm3 != 4)
  3864                 MOZ_CRASH();
  3865             int esize = 8 * imm3;
  3866             int elements = 64 / esize;
  3867             int8_t from[8];
  3868             get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
  3869             int16_t to[8];
  3870             int e = 0;
  3871             while (e < elements) {
  3872                 to[e] = from[e];
  3873                 e++;
  3875             set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
  3876         } else {
  3877             MOZ_CRASH();
  3879         break;
  3880       case 7:
  3881         if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && instr->bit(4) == 1) {
  3882             // vmovl unsigned
  3883             int Vd = (instr->bit(22) << 4) | instr->vdValue();
  3884             int Vm = (instr->bit(5) << 4) | instr->vmValue();
  3885             int imm3 = instr->bits(21, 19);
  3886             if (imm3 != 1 && imm3 != 2 && imm3 != 4)
  3887                 MOZ_CRASH();
  3888             int esize = 8 * imm3;
  3889             int elements = 64 / esize;
  3890             uint8_t from[8];
  3891             get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
  3892             uint16_t to[8];
  3893             int e = 0;
  3894             while (e < elements) {
  3895                 to[e] = from[e];
  3896                 e++;
  3898             set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
  3899         } else {
  3900             MOZ_CRASH();
  3902         break;
  3903       case 8:
  3904         if (instr->bits(21, 20) == 0) {
  3905             // vst1
  3906             int Vd = (instr->bit(22) << 4) | instr->vdValue();
  3907             int Rn = instr->vnValue();
  3908             int type = instr->bits(11, 8);
  3909             int Rm = instr->vmValue();
  3910             int32_t address = get_register(Rn);
  3911             int regs = 0;
  3912             switch (type) {
  3913               case nlt_1:
  3914                 regs = 1;
  3915                 break;
  3916               case nlt_2:
  3917                 regs = 2;
  3918                 break;
  3919               case nlt_3:
  3920                 regs = 3;
  3921                 break;
  3922               case nlt_4:
  3923                 regs = 4;
  3924                 break;
  3925               default:
  3926                 MOZ_CRASH();
  3927                 break;
  3929             int r = 0;
  3930             while (r < regs) {
  3931                 uint32_t data[2];
  3932                 get_d_register(Vd + r, data);
  3933                 writeW(address, data[0], instr);
  3934                 writeW(address + 4, data[1], instr);
  3935                 address += 8;
  3936                 r++;
  3938             if (Rm != 15) {
  3939                 if (Rm == 13)
  3940                     set_register(Rn, address);
  3941                 else
  3942                     set_register(Rn, get_register(Rn) + get_register(Rm));
  3944         } else if (instr->bits(21, 20) == 2) {
  3945             // vld1
  3946             int Vd = (instr->bit(22) << 4) | instr->vdValue();
  3947             int Rn = instr->vnValue();
  3948             int type = instr->bits(11, 8);
  3949             int Rm = instr->vmValue();
  3950             int32_t address = get_register(Rn);
  3951             int regs = 0;
  3952             switch (type) {
  3953               case nlt_1:
  3954                 regs = 1;
  3955                 break;
  3956               case nlt_2:
  3957                 regs = 2;
  3958                 break;
  3959               case nlt_3:
  3960                 regs = 3;
  3961                 break;
  3962               case nlt_4:
  3963                 regs = 4;
  3964                 break;
  3965               default:
  3966                 MOZ_CRASH();
  3967                 break;
  3969             int r = 0;
  3970             while (r < regs) {
  3971                 uint32_t data[2];
  3972                 data[0] = readW(address, instr);
  3973                 data[1] = readW(address + 4, instr);
  3974                 set_d_register(Vd + r, data);
  3975                 address += 8;
  3976                 r++;
  3978             if (Rm != 15) {
  3979                 if (Rm == 13)
  3980                     set_register(Rn, address);
  3981                 else
  3982                     set_register(Rn, get_register(Rn) + get_register(Rm));
  3984         } else {
  3985             MOZ_CRASH();
  3987         break;
  3988       case 0xA:
  3989       case 0xB:
  3990         if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
  3991             // pld: ignore instruction.
  3992         } else {
  3993             MOZ_CRASH();
  3995         break;
  3996       default:
  3997         MOZ_CRASH();
  4001 // Executes the current instruction.
  4002 void
  4003 Simulator::instructionDecode(SimInstruction *instr)
  4005     if (Simulator::ICacheCheckingEnabled) {
  4006         AutoLockSimulatorRuntime alsr(srt_);
  4007         CheckICache(srt_->icache(), instr);
  4010     pc_modified_ = false;
  4012     static const uint32_t kSpecialCondition = 15 << 28;
  4013     if (instr->conditionField() == kSpecialCondition) {
  4014         decodeSpecialCondition(instr);
  4015     } else if (conditionallyExecute(instr)) {
  4016         switch (instr->typeValue()) {
  4017           case 0:
  4018           case 1:
  4019             decodeType01(instr);
  4020             break;
  4021           case 2:
  4022             decodeType2(instr);
  4023             break;
  4024           case 3:
  4025             decodeType3(instr);
  4026             break;
  4027           case 4:
  4028             decodeType4(instr);
  4029             break;
  4030           case 5:
  4031             decodeType5(instr);
  4032             break;
  4033           case 6:
  4034             decodeType6(instr);
  4035             break;
  4036           case 7:
  4037             decodeType7(instr);
  4038             break;
  4039           default:
  4040             MOZ_CRASH();
  4041             break;
  4043         // If the instruction is a non taken conditional stop, we need to skip the
  4044         // inlined message address.
  4045     } else if (instr->isStop()) {
  4046         set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
  4048     if (!pc_modified_)
  4049         set_register(pc, reinterpret_cast<int32_t>(instr) + SimInstruction::kInstrSize);
  4053 template<bool EnableStopSimAt>
  4054 void
  4055 Simulator::execute()
  4057     // Get the PC to simulate. Cannot use the accessor here as we need the
  4058     // raw PC value and not the one used as input to arithmetic instructions.
  4059     int program_counter = get_pc();
  4060     AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread();
  4062     while (program_counter != end_sim_pc) {
  4063         if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) {
  4064             fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_);
  4065             ArmDebugger dbg(this);
  4066             dbg.debug();
  4067         } else {
  4068             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
  4069             instructionDecode(instr);
  4070             icount_++;
  4072             int32_t rpc = resume_pc_;
  4073             if (MOZ_UNLIKELY(rpc != 0)) {
  4074                 // AsmJS signal handler ran and we have to adjust the pc.
  4075                 activation->setInterrupted((void *)get_pc());
  4076                 set_pc(rpc);
  4077                 resume_pc_ = 0;
  4080         program_counter = get_pc();
  4084 void
  4085 Simulator::callInternal(uint8_t *entry)
  4087     // Prepare to execute the code at entry.
  4088     set_register(pc, reinterpret_cast<int32_t>(entry));
  4090     // Put down marker for end of simulation. The simulator will stop simulation
  4091     // when the PC reaches this value. By saving the "end simulation" value into
  4092     // the LR the simulation stops when returning to this call point.
  4093     set_register(lr, end_sim_pc);
  4095     // Remember the values of callee-saved registers.
  4096     // The code below assumes that r9 is not used as sb (static base) in
  4097     // simulator code and therefore is regarded as a callee-saved register.
  4098     int32_t r4_val = get_register(r4);
  4099     int32_t r5_val = get_register(r5);
  4100     int32_t r6_val = get_register(r6);
  4101     int32_t r7_val = get_register(r7);
  4102     int32_t r8_val = get_register(r8);
  4103     int32_t r9_val = get_register(r9);
  4104     int32_t r10_val = get_register(r10);
  4105     int32_t r11_val = get_register(r11);
  4107     // Remember d8 to d15 which are callee-saved.
  4108     uint64_t d8_val;
  4109     get_d_register(d8, &d8_val);
  4110     uint64_t d9_val;
  4111     get_d_register(d9, &d9_val);
  4112     uint64_t d10_val;
  4113     get_d_register(d10, &d10_val);
  4114     uint64_t d11_val;
  4115     get_d_register(d11, &d11_val);
  4116     uint64_t d12_val;
  4117     get_d_register(d12, &d12_val);
  4118     uint64_t d13_val;
  4119     get_d_register(d13, &d13_val);
  4120     uint64_t d14_val;
  4121     get_d_register(d14, &d14_val);
  4122     uint64_t d15_val;
  4123     get_d_register(d15, &d15_val);
  4125     // Set up the callee-saved registers with a known value. To be able to check
  4126     // that they are preserved properly across JS execution.
  4127     int32_t callee_saved_value = uint32_t(icount_);
  4128     set_register(r4, callee_saved_value);
  4129     set_register(r5, callee_saved_value);
  4130     set_register(r6, callee_saved_value);
  4131     set_register(r7, callee_saved_value);
  4132     set_register(r8, callee_saved_value);
  4133     set_register(r9, callee_saved_value);
  4134     set_register(r10, callee_saved_value);
  4135     set_register(r11, callee_saved_value);
  4137     uint64_t callee_saved_value_d = uint64_t(icount_);
  4138     set_d_register(d8, &callee_saved_value_d);
  4139     set_d_register(d9, &callee_saved_value_d);
  4140     set_d_register(d10, &callee_saved_value_d);
  4141     set_d_register(d11, &callee_saved_value_d);
  4142     set_d_register(d12, &callee_saved_value_d);
  4143     set_d_register(d13, &callee_saved_value_d);
  4144     set_d_register(d14, &callee_saved_value_d);
  4145     set_d_register(d15, &callee_saved_value_d);
  4147     // Start the simulation
  4148     if (Simulator::StopSimAt != -1L)
  4149         execute<true>();
  4150     else
  4151         execute<false>();
  4153     // Check that the callee-saved registers have been preserved.
  4154     MOZ_ASSERT(callee_saved_value == get_register(r4));
  4155     MOZ_ASSERT(callee_saved_value == get_register(r5));
  4156     MOZ_ASSERT(callee_saved_value == get_register(r6));
  4157     MOZ_ASSERT(callee_saved_value == get_register(r7));
  4158     MOZ_ASSERT(callee_saved_value == get_register(r8));
  4159     MOZ_ASSERT(callee_saved_value == get_register(r9));
  4160     MOZ_ASSERT(callee_saved_value == get_register(r10));
  4161     MOZ_ASSERT(callee_saved_value == get_register(r11));
  4163     uint64_t value;
  4164     get_d_register(d8, &value);
  4165     MOZ_ASSERT(callee_saved_value_d == value);
  4166     get_d_register(d9, &value);
  4167     MOZ_ASSERT(callee_saved_value_d == value);
  4168     get_d_register(d10, &value);
  4169     MOZ_ASSERT(callee_saved_value_d == value);
  4170     get_d_register(d11, &value);
  4171     MOZ_ASSERT(callee_saved_value_d == value);
  4172     get_d_register(d12, &value);
  4173     MOZ_ASSERT(callee_saved_value_d == value);
  4174     get_d_register(d13, &value);
  4175     MOZ_ASSERT(callee_saved_value_d == value);
  4176     get_d_register(d14, &value);
  4177     MOZ_ASSERT(callee_saved_value_d == value);
  4178     get_d_register(d15, &value);
  4179     MOZ_ASSERT(callee_saved_value_d == value);
  4181     // Restore callee-saved registers with the original value.
  4182     set_register(r4, r4_val);
  4183     set_register(r5, r5_val);
  4184     set_register(r6, r6_val);
  4185     set_register(r7, r7_val);
  4186     set_register(r8, r8_val);
  4187     set_register(r9, r9_val);
  4188     set_register(r10, r10_val);
  4189     set_register(r11, r11_val);
  4191     set_d_register(d8, &d8_val);
  4192     set_d_register(d9, &d9_val);
  4193     set_d_register(d10, &d10_val);
  4194     set_d_register(d11, &d11_val);
  4195     set_d_register(d12, &d12_val);
  4196     set_d_register(d13, &d13_val);
  4197     set_d_register(d14, &d14_val);
  4198     set_d_register(d15, &d15_val);
  4201 int64_t
  4202 Simulator::call(uint8_t* entry, int argument_count, ...)
  4204     va_list parameters;
  4205     va_start(parameters, argument_count);
  4207     // First four arguments passed in registers.
  4208     MOZ_ASSERT(argument_count >= 2);
  4209     set_register(r0, va_arg(parameters, int32_t));
  4210     set_register(r1, va_arg(parameters, int32_t));
  4211     if (argument_count >= 3)
  4212         set_register(r2, va_arg(parameters, int32_t));
  4213     if (argument_count >= 4)
  4214         set_register(r3, va_arg(parameters, int32_t));
  4216     // Remaining arguments passed on stack.
  4217     int original_stack = get_register(sp);
  4218     int entry_stack = original_stack;
  4219     if (argument_count >= 4)
  4220         entry_stack -= (argument_count - 4) * sizeof(int32_t);
  4222     entry_stack &= ~StackAlignment;
  4224     // Store remaining arguments on stack, from low to high memory.
  4225     intptr_t *stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
  4226     for (int i = 4; i < argument_count; i++)
  4227         stack_argument[i - 4] = va_arg(parameters, int32_t);
  4228     va_end(parameters);
  4229     set_register(sp, entry_stack);
  4231     callInternal(entry);
  4233     // Pop stack passed arguments.
  4234     MOZ_ASSERT(entry_stack == get_register(sp));
  4235     set_register(sp, original_stack);
  4237     int64_t result = (int64_t(get_register(r1)) << 32) | get_register(r0);
  4238     return result;
  4241 Simulator *
  4242 Simulator::Current()
  4244     PerThreadData *pt = TlsPerThreadData.get();
  4245     Simulator *sim = pt->simulator();
  4246     if (!sim) {
  4247         sim = js_new<Simulator>(pt->simulatorRuntime());
  4248         pt->setSimulator(sim);
  4251     return sim;
  4254 } // namespace jit
  4255 } // namespace js
  4257 js::jit::Simulator *
  4258 js::PerThreadData::simulator() const
  4260     return simulator_;
  4263 void
  4264 js::PerThreadData::setSimulator(js::jit::Simulator *sim)
  4266     simulator_ = sim;
  4267     simulatorStackLimit_ = sim->stackLimit();
  4270 js::jit::SimulatorRuntime *
  4271 js::PerThreadData::simulatorRuntime() const
  4273     return runtime_->simulatorRuntime();
  4276 uintptr_t *
  4277 js::PerThreadData::addressOfSimulatorStackLimit()
  4279     return &simulatorStackLimit_;
  4282 js::jit::SimulatorRuntime *
  4283 JSRuntime::simulatorRuntime() const
  4285     return simulatorRuntime_;
  4288 void
  4289 JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
  4291     MOZ_ASSERT(!simulatorRuntime_);
  4292     simulatorRuntime_ = srt;

mercurial