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