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