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