tor-browser

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

Simulator-mips64.h (16551B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 // Copyright 2011 the V8 project authors. All rights reserved.
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 //       notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 //       copyright notice, this list of conditions and the following
     12 //       disclaimer in the documentation and/or other materials provided
     13 //       with the distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 //       contributors may be used to endorse or promote products derived
     16 //       from this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #ifndef jit_mips64_Simulator_mips64_h
     31 #define jit_mips64_Simulator_mips64_h
     32 
     33 #ifdef JS_SIMULATOR_MIPS64
     34 
     35 #  include "mozilla/Atomics.h"
     36 
     37 #  include "jit/IonTypes.h"
     38 #  include "js/ProfilingFrameIterator.h"
     39 #  include "threading/Thread.h"
     40 #  include "vm/MutexIDs.h"
     41 #  include "wasm/WasmSignalHandlers.h"
     42 
     43 namespace js {
     44 
     45 namespace jit {
     46 
     47 class JitActivation;
     48 
     49 class Simulator;
     50 class Redirection;
     51 class CachePage;
     52 class AutoLockSimulator;
     53 
     54 // When the SingleStepCallback is called, the simulator is about to execute
     55 // sim->get_pc() and the current machine state represents the completed
     56 // execution of the previous pc.
     57 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc);
     58 
     59 const intptr_t kPointerAlignment = 8;
     60 const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
     61 
     62 const intptr_t kDoubleAlignment = 8;
     63 const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1;
     64 
     65 // Number of general purpose registers.
     66 const int kNumRegisters = 32;
     67 
     68 // In the simulator, the PC register is simulated as the 34th register.
     69 const int kPCRegister = 34;
     70 
     71 // Number coprocessor registers.
     72 const int kNumFPURegisters = 32;
     73 
     74 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
     75 const int kFCSRRegister = 31;
     76 const int kInvalidFPUControlRegister = -1;
     77 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
     78 const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1;
     79 
     80 // FCSR constants.
     81 const uint32_t kFCSRInexactFlagBit = 2;
     82 const uint32_t kFCSRUnderflowFlagBit = 3;
     83 const uint32_t kFCSROverflowFlagBit = 4;
     84 const uint32_t kFCSRDivideByZeroFlagBit = 5;
     85 const uint32_t kFCSRInvalidOpFlagBit = 6;
     86 
     87 const uint32_t kFCSRInexactCauseBit = 12;
     88 const uint32_t kFCSRUnderflowCauseBit = 13;
     89 const uint32_t kFCSROverflowCauseBit = 14;
     90 const uint32_t kFCSRDivideByZeroCauseBit = 15;
     91 const uint32_t kFCSRInvalidOpCauseBit = 16;
     92 
     93 const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
     94 const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
     95 const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
     96 const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
     97 const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
     98 
     99 const uint32_t kFCSRFlagMask =
    100    kFCSRInexactFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowFlagMask |
    101    kFCSRDivideByZeroFlagMask | kFCSRInvalidOpFlagMask;
    102 
    103 const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask;
    104 
    105 // On MIPS64 Simulator breakpoints can have different codes:
    106 // - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints,
    107 //   the simulator will run through them and print the registers.
    108 // - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop()
    109 //   instructions (see Assembler::stop()).
    110 // - Breaks larger than kMaxStopCode are simple breaks, dropping you into the
    111 //   debugger.
    112 const uint32_t kMaxWatchpointCode = 31;
    113 const uint32_t kMaxStopCode = 127;
    114 const uint32_t kWasmTrapCode = 6;
    115 
    116 // -----------------------------------------------------------------------------
    117 // Utility functions
    118 
    119 typedef uint32_t Instr;
    120 class SimInstruction;
    121 
    122 // Per thread simulator state.
    123 class Simulator {
    124  friend class MipsDebugger;
    125 
    126 public:
    127  // Registers are declared in order. See "See MIPS Run Linux" chapter 2.
    128  enum Register {
    129    no_reg = -1,
    130    zero_reg = 0,
    131    at,
    132    v0,
    133    v1,
    134    a0,
    135    a1,
    136    a2,
    137    a3,
    138    a4,
    139    a5,
    140    a6,
    141    a7,
    142    t4,
    143    t5,
    144    t6,
    145    t7,
    146    s0,
    147    s1,
    148    s2,
    149    s3,
    150    s4,
    151    s5,
    152    s6,
    153    s7,
    154    t8,
    155    t9,
    156    k0,
    157    k1,
    158    gp,
    159    sp,
    160    s8,
    161    ra,
    162    // LO, HI, and pc.
    163    LO,
    164    HI,
    165    pc,  // pc must be the last register.
    166    kNumSimuRegisters,
    167    // aliases
    168    fp = s8
    169  };
    170 
    171  // Coprocessor registers.
    172  enum FPURegister {
    173    f0,
    174    f1,
    175    f2,
    176    f3,
    177    f4,
    178    f5,
    179    f6,
    180    f7,
    181    f8,
    182    f9,
    183    f10,
    184    f11,
    185    f12,
    186    f13,
    187    f14,
    188    f15,
    189    f16,
    190    f17,
    191    f18,
    192    f19,
    193    f20,
    194    f21,
    195    f22,
    196    f23,
    197    f24,
    198    f25,
    199    f26,
    200    f27,
    201    f28,
    202    f29,
    203    f30,
    204    f31,
    205    kNumFPURegisters
    206  };
    207 
    208  // Returns nullptr on OOM.
    209  static Simulator* Create();
    210 
    211  static void Destroy(Simulator* simulator);
    212 
    213  // Constructor/destructor are for internal use only; use the static methods
    214  // above.
    215  Simulator();
    216  ~Simulator();
    217 
    218  // The currently executing Simulator instance. Potentially there can be one
    219  // for each native thread.
    220  static Simulator* Current();
    221 
    222  static inline uintptr_t StackLimit() {
    223    return Simulator::Current()->stackLimit();
    224  }
    225 
    226  uintptr_t* addressOfStackLimit();
    227 
    228  // Accessors for register state. Reading the pc value adheres to the MIPS
    229  // architecture specification and is off by a 8 from the currently executing
    230  // instruction.
    231  void setRegister(int reg, int64_t value);
    232  int64_t getRegister(int reg) const;
    233  // Same for FPURegisters.
    234  void setFpuRegister(int fpureg, int64_t value);
    235  void setFpuRegisterLo(int fpureg, int32_t value);
    236  void setFpuRegisterHi(int fpureg, int32_t value);
    237  void setFpuRegisterFloat(int fpureg, float value);
    238  void setFpuRegisterDouble(int fpureg, double value);
    239  int64_t getFpuRegister(int fpureg) const;
    240  int32_t getFpuRegisterLo(int fpureg) const;
    241  int32_t getFpuRegisterHi(int fpureg) const;
    242  float getFpuRegisterFloat(int fpureg) const;
    243  double getFpuRegisterDouble(int fpureg) const;
    244  void setFCSRBit(uint32_t cc, bool value);
    245  bool testFCSRBit(uint32_t cc);
    246  template <typename T>
    247  bool setFCSRRoundError(double original, double rounded);
    248 
    249  // Special case of set_register and get_register to access the raw PC value.
    250  void set_pc(int64_t value);
    251  int64_t get_pc() const;
    252 
    253  template <typename T>
    254  T get_pc_as() const {
    255    return reinterpret_cast<T>(get_pc());
    256  }
    257 
    258  void enable_single_stepping(SingleStepCallback cb, void* arg);
    259  void disable_single_stepping();
    260 
    261  // Accessor to the internal simulator stack area.
    262  uintptr_t stackLimit() const;
    263  bool overRecursed(uintptr_t newsp = 0) const;
    264  bool overRecursedWithExtra(uint32_t extra) const;
    265 
    266  // Executes MIPS instructions until the PC reaches end_sim_pc.
    267  template <bool enableStopSimAt>
    268  void execute();
    269 
    270  // Sets up the simulator state and grabs the result on return.
    271  int64_t call(uint8_t* entry, int argument_count, ...);
    272 
    273  // Push an address onto the JS stack.
    274  uintptr_t pushAddress(uintptr_t address);
    275 
    276  // Pop an address from the JS stack.
    277  uintptr_t popAddress();
    278 
    279  // Debugger input.
    280  void setLastDebuggerInput(char* input);
    281  char* lastDebuggerInput() { return lastDebuggerInput_; }
    282 
    283  // Returns true if pc register contains one of the 'SpecialValues' defined
    284  // below (bad_ra, end_sim_pc).
    285  bool has_bad_pc() const;
    286 
    287 private:
    288  enum SpecialValues {
    289    // Known bad pc value to ensure that the simulator does not execute
    290    // without being properly setup.
    291    bad_ra = -1,
    292    // A pc value used to signal the simulator to stop execution.  Generally
    293    // the ra is set to this value on transition from native C code to
    294    // simulated execution, so that the simulator can "return" to the native
    295    // C code.
    296    end_sim_pc = -2,
    297    // Unpredictable value.
    298    Unpredictable = 0xbadbeaf
    299  };
    300 
    301  bool init();
    302 
    303  // Unsupported instructions use Format to print an error and stop execution.
    304  void format(SimInstruction* instr, const char* format);
    305 
    306  // Read and write memory.
    307  inline uint8_t readBU(uint64_t addr, SimInstruction* instr);
    308  inline int8_t readB(uint64_t addr, SimInstruction* instr);
    309  inline void writeB(uint64_t addr, uint8_t value, SimInstruction* instr);
    310  inline void writeB(uint64_t addr, int8_t value, SimInstruction* instr);
    311 
    312  inline uint16_t readHU(uint64_t addr, SimInstruction* instr);
    313  inline int16_t readH(uint64_t addr, SimInstruction* instr);
    314  inline void writeH(uint64_t addr, uint16_t value, SimInstruction* instr);
    315  inline void writeH(uint64_t addr, int16_t value, SimInstruction* instr);
    316 
    317  inline uint32_t readWU(uint64_t addr, SimInstruction* instr);
    318  inline int32_t readW(uint64_t addr, SimInstruction* instr);
    319  inline void writeW(uint64_t addr, uint32_t value, SimInstruction* instr);
    320  inline void writeW(uint64_t addr, int32_t value, SimInstruction* instr);
    321 
    322  inline int64_t readDW(uint64_t addr, SimInstruction* instr);
    323  inline int64_t readDWL(uint64_t addr, SimInstruction* instr);
    324  inline int64_t readDWR(uint64_t addr, SimInstruction* instr);
    325  inline void writeDW(uint64_t addr, int64_t value, SimInstruction* instr);
    326 
    327  inline double readD(uint64_t addr, SimInstruction* instr);
    328  inline void writeD(uint64_t addr, double value, SimInstruction* instr);
    329 
    330  inline int32_t loadLinkedW(uint64_t addr, SimInstruction* instr);
    331  inline int storeConditionalW(uint64_t addr, int32_t value,
    332                               SimInstruction* instr);
    333 
    334  inline int64_t loadLinkedD(uint64_t addr, SimInstruction* instr);
    335  inline int storeConditionalD(uint64_t addr, int64_t value,
    336                               SimInstruction* instr);
    337 
    338  // Helper function for decodeTypeRegister.
    339  void configureTypeRegister(SimInstruction* instr, int64_t& alu_out,
    340                             __int128& i128hilo, unsigned __int128& u128hilo,
    341                             int64_t& next_pc, int32_t& return_addr_reg,
    342                             bool& do_interrupt);
    343 
    344  // Executing is handled based on the instruction type.
    345  void decodeTypeRegister(SimInstruction* instr);
    346  void decodeTypeImmediate(SimInstruction* instr);
    347  void decodeTypeJump(SimInstruction* instr);
    348 
    349  // Used for breakpoints and traps.
    350  void softwareInterrupt(SimInstruction* instr);
    351 
    352  // Stop helper functions.
    353  bool isWatchpoint(uint32_t code);
    354  void printWatchpoint(uint32_t code);
    355  void handleStop(uint32_t code, SimInstruction* instr);
    356  bool isStopInstruction(SimInstruction* instr);
    357  bool isEnabledStop(uint32_t code);
    358  void enableStop(uint32_t code);
    359  void disableStop(uint32_t code);
    360  void increaseStopCounter(uint32_t code);
    361  void printStopInfo(uint32_t code);
    362 
    363  JS::ProfilingFrameIterator::RegisterState registerState();
    364 
    365  // Handle any wasm faults, returning true if the fault was handled.
    366  // This method is rather hot so inline the normal (no-wasm) case.
    367  bool MOZ_ALWAYS_INLINE handleWasmSegFault(uint64_t addr, unsigned numBytes) {
    368    if (MOZ_LIKELY(!js::wasm::CodeExists)) {
    369      return false;
    370    }
    371 
    372    uint8_t* newPC;
    373    if (!js::wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes,
    374                                     &newPC)) {
    375      return false;
    376    }
    377 
    378    LLBit_ = false;
    379    set_pc(int64_t(newPC));
    380    return true;
    381  }
    382 
    383  // Executes one instruction.
    384  void instructionDecode(SimInstruction* instr);
    385  // Execute one instruction placed in a branch delay slot.
    386  void branchDelayInstructionDecode(SimInstruction* instr);
    387 
    388 public:
    389  static int64_t StopSimAt;
    390 
    391  // Runtime call support.
    392  static void* RedirectNativeFunction(void* nativeFunction,
    393                                      ABIFunctionType type);
    394 
    395 private:
    396  enum Exception {
    397    kNone,
    398    kIntegerOverflow,
    399    kIntegerUnderflow,
    400    kDivideByZero,
    401    kNumExceptions
    402  };
    403  int16_t exceptions[kNumExceptions];
    404 
    405  // Exceptions.
    406  void signalExceptions();
    407 
    408  // Handle return value for runtime FP functions.
    409  void setCallResultDouble(double result);
    410  void setCallResultFloat(float result);
    411  void setCallResult(int64_t res);
    412 #  ifdef XP_DARWIN
    413  // add a dedicated setCallResult for intptr_t on Darwin
    414  void setCallResult(intptr_t res);
    415 #  endif
    416  void setCallResult(__int128 res);
    417 
    418  void callInternal(uint8_t* entry);
    419 
    420  // Architecture state.
    421  // Registers.
    422  int64_t registers_[kNumSimuRegisters];
    423  // Coprocessor Registers.
    424  int64_t FPUregisters_[kNumFPURegisters];
    425  // FPU control register.
    426  uint32_t FCSR_;
    427 
    428  bool LLBit_;
    429  uintptr_t LLAddr_;
    430  int64_t lastLLValue_;
    431 
    432  // Simulator support.
    433  char* stack_;
    434  uintptr_t stackLimit_;
    435  bool pc_modified_;
    436  int64_t icount_;
    437  int64_t break_count_;
    438 
    439  // Debugger input.
    440  char* lastDebuggerInput_;
    441 
    442  // Registered breakpoints.
    443  SimInstruction* break_pc_;
    444  Instr break_instr_;
    445 
    446  // Single-stepping support
    447  bool single_stepping_;
    448  SingleStepCallback single_step_callback_;
    449  void* single_step_callback_arg_;
    450 
    451  // A stop is watched if its code is less than kNumOfWatchedStops.
    452  // Only watched stops support enabling/disabling and the counter feature.
    453  static const uint32_t kNumOfWatchedStops = 256;
    454 
    455  // Stop is disabled if bit 31 is set.
    456  static const uint32_t kStopDisabledBit = 1U << 31;
    457 
    458  // A stop is enabled, meaning the simulator will stop when meeting the
    459  // instruction, if bit 31 of watchedStops_[code].count is unset.
    460  // The value watchedStops_[code].count & ~(1 << 31) indicates how many times
    461  // the breakpoint was hit or gone through.
    462  struct StopCountAndDesc {
    463    uint32_t count_;
    464    char* desc_;
    465  };
    466  StopCountAndDesc watchedStops_[kNumOfWatchedStops];
    467 };
    468 
    469 // Process wide simulator state.
    470 class SimulatorProcess {
    471  friend class Redirection;
    472  friend class AutoLockSimulatorCache;
    473 
    474 private:
    475  // ICache checking.
    476  struct ICacheHasher {
    477    typedef void* Key;
    478    typedef void* Lookup;
    479    static HashNumber hash(const Lookup& l);
    480    static bool match(const Key& k, const Lookup& l);
    481  };
    482 
    483 public:
    484  typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
    485 
    486  static mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    487      ICacheCheckingDisableCount;
    488  static void FlushICache(void* start, size_t size);
    489 
    490  static void checkICacheLocked(SimInstruction* instr);
    491 
    492  static bool initialize() {
    493    singleton_ = js_new<SimulatorProcess>();
    494    return singleton_;
    495  }
    496  static void destroy() {
    497    js_delete(singleton_);
    498    singleton_ = nullptr;
    499  }
    500 
    501  SimulatorProcess();
    502  ~SimulatorProcess();
    503 
    504 private:
    505  static SimulatorProcess* singleton_;
    506 
    507  // This lock creates a critical section around 'redirection_' and
    508  // 'icache_', which are referenced both by the execution engine
    509  // and by the off-thread compiler (see Redirection::Get in the cpp file).
    510  Mutex cacheLock_ MOZ_UNANNOTATED;
    511 
    512  Redirection* redirection_;
    513  ICacheMap icache_;
    514 
    515 public:
    516  static ICacheMap& icache() {
    517    // Technically we need the lock to access the innards of the
    518    // icache, not to take its address, but the latter condition
    519    // serves as a useful complement to the former.
    520    singleton_->cacheLock_.assertOwnedByCurrentThread();
    521    return singleton_->icache_;
    522  }
    523 
    524  static Redirection* redirection() {
    525    singleton_->cacheLock_.assertOwnedByCurrentThread();
    526    return singleton_->redirection_;
    527  }
    528 
    529  static void setRedirection(js::jit::Redirection* redirection) {
    530    singleton_->cacheLock_.assertOwnedByCurrentThread();
    531    singleton_->redirection_ = redirection;
    532  }
    533 };
    534 
    535 }  // namespace jit
    536 }  // namespace js
    537 
    538 #endif /* JS_SIMULATOR_MIPS64 */
    539 
    540 #endif /* jit_mips64_Simulator_mips64_h */