Home | History | Annotate | Download | only in mips
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 // Declares a Simulator for MIPS instructions if we are not generating a native
      7 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
      8 // on regular desktop machines.
      9 // V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
     10 // which will start execution in the Simulator or forwards to the real entry
     11 // on a MIPS HW platform.
     12 
     13 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
     14 #define V8_MIPS_SIMULATOR_MIPS_H_
     15 
     16 #include "src/allocation.h"
     17 #include "src/mips/constants-mips.h"
     18 
     19 #if !defined(USE_SIMULATOR)
     20 // Running without a simulator on a native mips platform.
     21 
     22 namespace v8 {
     23 namespace internal {
     24 
     25 // When running without a simulator we call the entry directly.
     26 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
     27   entry(p0, p1, p2, p3, p4)
     28 
     29 typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
     30                                    void*, int*, int, Address, int, Isolate*);
     31 
     32 
     33 // Call the generated regexp code directly. The code at the entry address
     34 // should act as a function matching the type arm_regexp_matcher.
     35 // The fifth argument is a dummy that reserves the space used for
     36 // the return address added by the ExitFrame in native calls.
     37 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
     38                                    p7, p8)                                     \
     39   (FUNCTION_CAST<mips_regexp_matcher>(entry)(p0, p1, p2, p3, NULL, p4, p5, p6, \
     40                                              p7, p8))
     41 
     42 // The stack limit beyond which we will throw stack overflow errors in
     43 // generated code. Because generated code on mips uses the C stack, we
     44 // just use the C stack limit.
     45 class SimulatorStack : public v8::internal::AllStatic {
     46  public:
     47   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
     48                                             uintptr_t c_limit) {
     49     return c_limit;
     50   }
     51 
     52   static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
     53                                             uintptr_t try_catch_address) {
     54     USE(isolate);
     55     return try_catch_address;
     56   }
     57 
     58   static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); }
     59 };
     60 
     61 }  // namespace internal
     62 }  // namespace v8
     63 
     64 // Calculated the stack limit beyond which we will throw stack overflow errors.
     65 // This macro must be called from a C++ method. It relies on being able to take
     66 // the address of "this" to get a value on the current execution stack and then
     67 // calculates the stack limit based on that value.
     68 // NOTE: The check for overflow is not safe as there is no guarantee that the
     69 // running thread has its stack in all memory up to address 0x00000000.
     70 #define GENERATED_CODE_STACK_LIMIT(limit) \
     71   (reinterpret_cast<uintptr_t>(this) >= limit ? \
     72       reinterpret_cast<uintptr_t>(this) - limit : 0)
     73 
     74 #else  // !defined(USE_SIMULATOR)
     75 // Running with a simulator.
     76 
     77 #include "src/assembler.h"
     78 #include "src/hashmap.h"
     79 
     80 namespace v8 {
     81 namespace internal {
     82 
     83 // -----------------------------------------------------------------------------
     84 // Utility functions
     85 
     86 class CachePage {
     87  public:
     88   static const int LINE_VALID = 0;
     89   static const int LINE_INVALID = 1;
     90 
     91   static const int kPageShift = 12;
     92   static const int kPageSize = 1 << kPageShift;
     93   static const int kPageMask = kPageSize - 1;
     94   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
     95   static const int kLineLength = 1 << kLineShift;
     96   static const int kLineMask = kLineLength - 1;
     97 
     98   CachePage() {
     99     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
    100   }
    101 
    102   char* ValidityByte(int offset) {
    103     return &validity_map_[offset >> kLineShift];
    104   }
    105 
    106   char* CachedData(int offset) {
    107     return &data_[offset];
    108   }
    109 
    110  private:
    111   char data_[kPageSize];   // The cached data.
    112   static const int kValidityMapSize = kPageSize >> kLineShift;
    113   char validity_map_[kValidityMapSize];  // One byte per line.
    114 };
    115 
    116 class Simulator {
    117  public:
    118   friend class MipsDebugger;
    119 
    120   // Registers are declared in order. See SMRL chapter 2.
    121   enum Register {
    122     no_reg = -1,
    123     zero_reg = 0,
    124     at,
    125     v0, v1,
    126     a0, a1, a2, a3,
    127     t0, t1, t2, t3, t4, t5, t6, t7,
    128     s0, s1, s2, s3, s4, s5, s6, s7,
    129     t8, t9,
    130     k0, k1,
    131     gp,
    132     sp,
    133     s8,
    134     ra,
    135     // LO, HI, and pc.
    136     LO,
    137     HI,
    138     pc,   // pc must be the last register.
    139     kNumSimuRegisters,
    140     // aliases
    141     fp = s8
    142   };
    143 
    144   // Coprocessor registers.
    145   // Generated code will always use doubles. So we will only use even registers.
    146   enum FPURegister {
    147     f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
    148     f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
    149     f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
    150     f26, f27, f28, f29, f30, f31,
    151     kNumFPURegisters
    152   };
    153 
    154   explicit Simulator(Isolate* isolate);
    155   ~Simulator();
    156 
    157   // The currently executing Simulator instance. Potentially there can be one
    158   // for each native thread.
    159   static Simulator* current(v8::internal::Isolate* isolate);
    160 
    161   // Accessors for register state. Reading the pc value adheres to the MIPS
    162   // architecture specification and is off by a 8 from the currently executing
    163   // instruction.
    164   void set_register(int reg, int32_t value);
    165   void set_dw_register(int dreg, const int* dbl);
    166   int32_t get_register(int reg) const;
    167   double get_double_from_register_pair(int reg);
    168   // Same for FPURegisters.
    169   void set_fpu_register(int fpureg, int64_t value);
    170   void set_fpu_register_word(int fpureg, int32_t value);
    171   void set_fpu_register_hi_word(int fpureg, int32_t value);
    172   void set_fpu_register_float(int fpureg, float value);
    173   void set_fpu_register_double(int fpureg, double value);
    174   void set_fpu_register_invalid_result64(float original, float rounded);
    175   void set_fpu_register_invalid_result(float original, float rounded);
    176   void set_fpu_register_word_invalid_result(float original, float rounded);
    177   void set_fpu_register_invalid_result64(double original, double rounded);
    178   void set_fpu_register_invalid_result(double original, double rounded);
    179   void set_fpu_register_word_invalid_result(double original, double rounded);
    180   int64_t get_fpu_register(int fpureg) const;
    181   int32_t get_fpu_register_word(int fpureg) const;
    182   int32_t get_fpu_register_signed_word(int fpureg) const;
    183   int32_t get_fpu_register_hi_word(int fpureg) const;
    184   float get_fpu_register_float(int fpureg) const;
    185   double get_fpu_register_double(int fpureg) const;
    186   void set_fcsr_bit(uint32_t cc, bool value);
    187   bool test_fcsr_bit(uint32_t cc);
    188   void set_fcsr_rounding_mode(FPURoundingMode mode);
    189   unsigned int get_fcsr_rounding_mode();
    190   bool set_fcsr_round_error(double original, double rounded);
    191   bool set_fcsr_round_error(float original, float rounded);
    192   bool set_fcsr_round64_error(double original, double rounded);
    193   bool set_fcsr_round64_error(float original, float rounded);
    194   void round_according_to_fcsr(double toRound, double& rounded,
    195                                int32_t& rounded_int, double fs);
    196   void round_according_to_fcsr(float toRound, float& rounded,
    197                                int32_t& rounded_int, float fs);
    198   void round64_according_to_fcsr(double toRound, double& rounded,
    199                                  int64_t& rounded_int, double fs);
    200   void round64_according_to_fcsr(float toRound, float& rounded,
    201                                  int64_t& rounded_int, float fs);
    202   // Special case of set_register and get_register to access the raw PC value.
    203   void set_pc(int32_t value);
    204   int32_t get_pc() const;
    205 
    206   Address get_sp() const {
    207     return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
    208   }
    209 
    210   // Accessor to the internal simulator stack area.
    211   uintptr_t StackLimit(uintptr_t c_limit) const;
    212 
    213   // Executes MIPS instructions until the PC reaches end_sim_pc.
    214   void Execute();
    215 
    216   // Call on program start.
    217   static void Initialize(Isolate* isolate);
    218 
    219   static void TearDown(HashMap* i_cache, Redirection* first);
    220 
    221   // V8 generally calls into generated JS code with 5 parameters and into
    222   // generated RegExp code with 7 parameters. This is a convenience function,
    223   // which sets up the simulator state and grabs the result on return.
    224   int32_t Call(byte* entry, int argument_count, ...);
    225   // Alternative: call a 2-argument double function.
    226   double CallFP(byte* entry, double d0, double d1);
    227 
    228   // Push an address onto the JS stack.
    229   uintptr_t PushAddress(uintptr_t address);
    230 
    231   // Pop an address from the JS stack.
    232   uintptr_t PopAddress();
    233 
    234   // Debugger input.
    235   void set_last_debugger_input(char* input);
    236   char* last_debugger_input() { return last_debugger_input_; }
    237 
    238   // ICache checking.
    239   static void FlushICache(v8::internal::HashMap* i_cache, void* start,
    240                           size_t size);
    241 
    242   // Returns true if pc register contains one of the 'special_values' defined
    243   // below (bad_ra, end_sim_pc).
    244   bool has_bad_pc() const;
    245 
    246  private:
    247   enum special_values {
    248     // Known bad pc value to ensure that the simulator does not execute
    249     // without being properly setup.
    250     bad_ra = -1,
    251     // A pc value used to signal the simulator to stop execution.  Generally
    252     // the ra is set to this value on transition from native C code to
    253     // simulated execution, so that the simulator can "return" to the native
    254     // C code.
    255     end_sim_pc = -2,
    256     // Unpredictable value.
    257     Unpredictable = 0xbadbeaf
    258   };
    259 
    260   // Unsupported instructions use Format to print an error and stop execution.
    261   void Format(Instruction* instr, const char* format);
    262 
    263   // Read and write memory.
    264   inline uint32_t ReadBU(int32_t addr);
    265   inline int32_t ReadB(int32_t addr);
    266   inline void WriteB(int32_t addr, uint8_t value);
    267   inline void WriteB(int32_t addr, int8_t value);
    268 
    269   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
    270   inline int16_t ReadH(int32_t addr, Instruction* instr);
    271   // Note: Overloaded on the sign of the value.
    272   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
    273   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
    274 
    275   inline int ReadW(int32_t addr, Instruction* instr);
    276   inline void WriteW(int32_t addr, int value, Instruction* instr);
    277 
    278   inline double ReadD(int32_t addr, Instruction* instr);
    279   inline void WriteD(int32_t addr, double value, Instruction* instr);
    280 
    281   // Helpers for data value tracing.
    282   enum TraceType {
    283     BYTE,
    284     HALF,
    285     WORD
    286     // DWORD,
    287     // DFLOAT - Floats may have printing issues due to paired lwc1's
    288   };
    289 
    290   void TraceRegWr(int32_t value);
    291   void TraceMemWr(int32_t addr, int32_t value, TraceType t);
    292   void TraceMemRd(int32_t addr, int32_t value);
    293   EmbeddedVector<char, 128> trace_buf_;
    294 
    295   // Operations depending on endianness.
    296   // Get Double Higher / Lower word.
    297   inline int32_t GetDoubleHIW(double* addr);
    298   inline int32_t GetDoubleLOW(double* addr);
    299   // Set Double Higher / Lower word.
    300   inline int32_t SetDoubleHIW(double* addr);
    301   inline int32_t SetDoubleLOW(double* addr);
    302 
    303   // Executing is handled based on the instruction type.
    304   void DecodeTypeRegister(Instruction* instr);
    305 
    306   // Functions called from DecodeTypeRegister.
    307   void DecodeTypeRegisterCOP1();
    308 
    309   void DecodeTypeRegisterCOP1X();
    310 
    311   void DecodeTypeRegisterSPECIAL();
    312 
    313   void DecodeTypeRegisterSPECIAL2();
    314 
    315   void DecodeTypeRegisterSPECIAL3();
    316 
    317   // Called from DecodeTypeRegisterCOP1.
    318   void DecodeTypeRegisterSRsType();
    319 
    320   void DecodeTypeRegisterDRsType();
    321 
    322   void DecodeTypeRegisterWRsType();
    323 
    324   void DecodeTypeRegisterLRsType();
    325 
    326   Instruction* currentInstr_;
    327 
    328   inline Instruction* get_instr() const { return currentInstr_; }
    329   inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
    330 
    331   inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
    332   inline int32_t rs() const { return get_register(rs_reg()); }
    333   inline uint32_t rs_u() const {
    334     return static_cast<uint32_t>(get_register(rs_reg()));
    335   }
    336   inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
    337   inline int32_t rt() const { return get_register(rt_reg()); }
    338   inline uint32_t rt_u() const {
    339     return static_cast<uint32_t>(get_register(rt_reg()));
    340   }
    341   inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
    342   inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
    343   inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
    344   inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
    345   inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
    346   inline int32_t sa() const { return currentInstr_->SaValue(); }
    347   inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
    348 
    349   inline void SetResult(int32_t rd_reg, int32_t alu_out) {
    350     set_register(rd_reg, alu_out);
    351     TraceRegWr(alu_out);
    352   }
    353 
    354   void DecodeTypeImmediate(Instruction* instr);
    355   void DecodeTypeJump(Instruction* instr);
    356 
    357   // Used for breakpoints and traps.
    358   void SoftwareInterrupt(Instruction* instr);
    359 
    360   // Compact branch guard.
    361   void CheckForbiddenSlot(int32_t current_pc) {
    362     Instruction* instr_aftter_compact_branch =
    363         reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
    364     if (instr_aftter_compact_branch->IsForbiddenInBranchDelay()) {
    365       V8_Fatal(__FILE__, __LINE__,
    366                "Error: Unexpected instruction 0x%08x immediately after a "
    367                "compact branch instruction.",
    368                *reinterpret_cast<uint32_t*>(instr_aftter_compact_branch));
    369     }
    370   }
    371 
    372   // Stop helper functions.
    373   bool IsWatchpoint(uint32_t code);
    374   void PrintWatchpoint(uint32_t code);
    375   void HandleStop(uint32_t code, Instruction* instr);
    376   bool IsStopInstruction(Instruction* instr);
    377   bool IsEnabledStop(uint32_t code);
    378   void EnableStop(uint32_t code);
    379   void DisableStop(uint32_t code);
    380   void IncreaseStopCounter(uint32_t code);
    381   void PrintStopInfo(uint32_t code);
    382 
    383 
    384   // Executes one instruction.
    385   void InstructionDecode(Instruction* instr);
    386   // Execute one instruction placed in a branch delay slot.
    387   void BranchDelayInstructionDecode(Instruction* instr) {
    388     if (instr->InstructionBits() == nopInstr) {
    389       // Short-cut generic nop instructions. They are always valid and they
    390       // never change the simulator state.
    391       return;
    392     }
    393 
    394     if (instr->IsForbiddenInBranchDelay()) {
    395       V8_Fatal(__FILE__, __LINE__,
    396                "Eror:Unexpected %i opcode in a branch delay slot.",
    397                instr->OpcodeValue());
    398     }
    399     InstructionDecode(instr);
    400     SNPrintF(trace_buf_, " ");
    401   }
    402 
    403   // ICache.
    404   static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
    405   static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
    406                            int size);
    407   static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
    408 
    409   enum Exception {
    410     none,
    411     kIntegerOverflow,
    412     kIntegerUnderflow,
    413     kDivideByZero,
    414     kNumExceptions
    415   };
    416 
    417   // Exceptions.
    418   void SignalException(Exception e);
    419 
    420   // Runtime call support.
    421   static void* RedirectExternalReference(Isolate* isolate,
    422                                          void* external_function,
    423                                          ExternalReference::Type type);
    424 
    425   // Handle arguments and return value for runtime FP functions.
    426   void GetFpArgs(double* x, double* y, int32_t* z);
    427   void SetFpResult(const double& result);
    428 
    429   void CallInternal(byte* entry);
    430 
    431   // Architecture state.
    432   // Registers.
    433   int32_t registers_[kNumSimuRegisters];
    434   // Coprocessor Registers.
    435   // Note: FP32 mode uses only the lower 32-bit part of each element,
    436   // the upper 32-bit is unpredictable.
    437   int64_t FPUregisters_[kNumFPURegisters];
    438   // FPU control register.
    439   uint32_t FCSR_;
    440 
    441   // Simulator support.
    442   // Allocate 1MB for stack.
    443   static const size_t stack_size_ = 1 * 1024*1024;
    444   char* stack_;
    445   bool pc_modified_;
    446   uint64_t icount_;
    447   int break_count_;
    448 
    449   // Debugger input.
    450   char* last_debugger_input_;
    451 
    452   // Icache simulation.
    453   v8::internal::HashMap* i_cache_;
    454 
    455   v8::internal::Isolate* isolate_;
    456 
    457   // Registered breakpoints.
    458   Instruction* break_pc_;
    459   Instr break_instr_;
    460 
    461   // Stop is disabled if bit 31 is set.
    462   static const uint32_t kStopDisabledBit = 1 << 31;
    463 
    464   // A stop is enabled, meaning the simulator will stop when meeting the
    465   // instruction, if bit 31 of watched_stops_[code].count is unset.
    466   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
    467   // the breakpoint was hit or gone through.
    468   struct StopCountAndDesc {
    469     uint32_t count;
    470     char* desc;
    471   };
    472   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
    473 };
    474 
    475 
    476 // When running with the simulator transition into simulated execution at this
    477 // point.
    478 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
    479   reinterpret_cast<Object*>(Simulator::current(isolate)->Call(  \
    480       FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
    481 
    482 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
    483                                    p7, p8)                                     \
    484   Simulator::current(isolate)                                                  \
    485       ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
    486 
    487 
    488 // The simulator has its own stack. Thus it has a different stack limit from
    489 // the C-based native code.  The JS-based limit normally points near the end of
    490 // the simulator stack.  When the C-based limit is exhausted we reflect that by
    491 // lowering the JS-based limit as well, to make stack checks trigger.
    492 class SimulatorStack : public v8::internal::AllStatic {
    493  public:
    494   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
    495                                             uintptr_t c_limit) {
    496     return Simulator::current(isolate)->StackLimit(c_limit);
    497   }
    498 
    499   static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
    500                                             uintptr_t try_catch_address) {
    501     Simulator* sim = Simulator::current(isolate);
    502     return sim->PushAddress(try_catch_address);
    503   }
    504 
    505   static inline void UnregisterCTryCatch(Isolate* isolate) {
    506     Simulator::current(isolate)->PopAddress();
    507   }
    508 };
    509 
    510 }  // namespace internal
    511 }  // namespace v8
    512 
    513 #endif  // !defined(USE_SIMULATOR)
    514 #endif  // V8_MIPS_SIMULATOR_MIPS_H_
    515