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