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