Upstream version 10.39.225.0
[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 "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/assembler.h"
74 #include "src/hashmap.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, int64_t value);
166   void set_fpu_register_word(int fpureg, int32_t value);
167   void set_fpu_register_hi_word(int fpureg, int32_t value);
168   void set_fpu_register_float(int fpureg, float value);
169   void set_fpu_register_double(int fpureg, double value);
170   int64_t get_fpu_register(int fpureg) const;
171   int32_t get_fpu_register_word(int fpureg) const;
172   int32_t get_fpu_register_signed_word(int fpureg) const;
173   int32_t get_fpu_register_hi_word(int fpureg) const;
174   float get_fpu_register_float(int fpureg) const;
175   double get_fpu_register_double(int fpureg) const;
176   void set_fcsr_bit(uint32_t cc, bool value);
177   bool test_fcsr_bit(uint32_t cc);
178   bool set_fcsr_round_error(double original, double rounded);
179
180   // Special case of set_register and get_register to access the raw PC value.
181   void set_pc(int32_t value);
182   int32_t get_pc() const;
183
184   Address get_sp() {
185     return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
186   }
187
188   // Accessor to the internal simulator stack area.
189   uintptr_t StackLimit() const;
190
191   // Executes MIPS instructions until the PC reaches end_sim_pc.
192   void Execute();
193
194   // Call on program start.
195   static void Initialize(Isolate* isolate);
196
197   // V8 generally calls into generated JS code with 5 parameters and into
198   // generated RegExp code with 7 parameters. This is a convenience function,
199   // which sets up the simulator state and grabs the result on return.
200   int32_t Call(byte* entry, int argument_count, ...);
201   // Alternative: call a 2-argument double function.
202   double CallFP(byte* entry, double d0, double d1);
203
204   // Push an address onto the JS stack.
205   uintptr_t PushAddress(uintptr_t address);
206
207   // Pop an address from the JS stack.
208   uintptr_t PopAddress();
209
210   // Debugger input.
211   void set_last_debugger_input(char* input);
212   char* last_debugger_input() { return last_debugger_input_; }
213
214   // ICache checking.
215   static void FlushICache(v8::internal::HashMap* i_cache, void* start,
216                           size_t size);
217
218   // Returns true if pc register contains one of the 'special_values' defined
219   // below (bad_ra, end_sim_pc).
220   bool has_bad_pc() const;
221
222  private:
223   enum special_values {
224     // Known bad pc value to ensure that the simulator does not execute
225     // without being properly setup.
226     bad_ra = -1,
227     // A pc value used to signal the simulator to stop execution.  Generally
228     // the ra is set to this value on transition from native C code to
229     // simulated execution, so that the simulator can "return" to the native
230     // C code.
231     end_sim_pc = -2,
232     // Unpredictable value.
233     Unpredictable = 0xbadbeaf
234   };
235
236   // Unsupported instructions use Format to print an error and stop execution.
237   void Format(Instruction* instr, const char* format);
238
239   // Read and write memory.
240   inline uint32_t ReadBU(int32_t addr);
241   inline int32_t ReadB(int32_t addr);
242   inline void WriteB(int32_t addr, uint8_t value);
243   inline void WriteB(int32_t addr, int8_t value);
244
245   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
246   inline int16_t ReadH(int32_t addr, Instruction* instr);
247   // Note: Overloaded on the sign of the value.
248   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
249   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
250
251   inline int ReadW(int32_t addr, Instruction* instr);
252   inline void WriteW(int32_t addr, int value, Instruction* instr);
253
254   inline double ReadD(int32_t addr, Instruction* instr);
255   inline void WriteD(int32_t addr, double value, Instruction* instr);
256
257   // Operations depending on endianness.
258   // Get Double Higher / Lower word.
259   inline int32_t GetDoubleHIW(double* addr);
260   inline int32_t GetDoubleLOW(double* addr);
261   // Set Double Higher / Lower word.
262   inline int32_t SetDoubleHIW(double* addr);
263   inline int32_t SetDoubleLOW(double* addr);
264
265   // Executing is handled based on the instruction type.
266   void DecodeTypeRegister(Instruction* instr);
267
268   // Helper function for DecodeTypeRegister.
269   void ConfigureTypeRegister(Instruction* instr,
270                              int32_t* alu_out,
271                              int64_t* i64hilo,
272                              uint64_t* u64hilo,
273                              int32_t* next_pc,
274                              int32_t* return_addr_reg,
275                              bool* do_interrupt);
276
277   void DecodeTypeImmediate(Instruction* instr);
278   void DecodeTypeJump(Instruction* instr);
279
280   // Used for breakpoints and traps.
281   void SoftwareInterrupt(Instruction* instr);
282
283   // Stop helper functions.
284   bool IsWatchpoint(uint32_t code);
285   void PrintWatchpoint(uint32_t code);
286   void HandleStop(uint32_t code, Instruction* instr);
287   bool IsStopInstruction(Instruction* instr);
288   bool IsEnabledStop(uint32_t code);
289   void EnableStop(uint32_t code);
290   void DisableStop(uint32_t code);
291   void IncreaseStopCounter(uint32_t code);
292   void PrintStopInfo(uint32_t code);
293
294
295   // Executes one instruction.
296   void InstructionDecode(Instruction* instr);
297   // Execute one instruction placed in a branch delay slot.
298   void BranchDelayInstructionDecode(Instruction* instr) {
299     if (instr->InstructionBits() == nopInstr) {
300       // Short-cut generic nop instructions. They are always valid and they
301       // never change the simulator state.
302       return;
303     }
304
305     if (instr->IsForbiddenInBranchDelay()) {
306       V8_Fatal(__FILE__, __LINE__,
307                "Eror:Unexpected %i opcode in a branch delay slot.",
308                instr->OpcodeValue());
309     }
310     InstructionDecode(instr);
311   }
312
313   // ICache.
314   static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
315   static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
316                            int size);
317   static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
318
319   enum Exception {
320     none,
321     kIntegerOverflow,
322     kIntegerUnderflow,
323     kDivideByZero,
324     kNumExceptions
325   };
326   int16_t exceptions[kNumExceptions];
327
328   // Exceptions.
329   void SignalExceptions();
330
331   // Runtime call support.
332   static void* RedirectExternalReference(void* external_function,
333                                          ExternalReference::Type type);
334
335   // Handle arguments and return value for runtime FP functions.
336   void GetFpArgs(double* x, double* y, int32_t* z);
337   void SetFpResult(const double& result);
338
339   void CallInternal(byte* entry);
340
341   // Architecture state.
342   // Registers.
343   int32_t registers_[kNumSimuRegisters];
344   // Coprocessor Registers.
345   // Note: FP32 mode uses only the lower 32-bit part of each element,
346   // the upper 32-bit is unpredictable.
347   int64_t FPUregisters_[kNumFPURegisters];
348   // FPU control register.
349   uint32_t FCSR_;
350
351   // Simulator support.
352   // Allocate 1MB for stack.
353   static const size_t stack_size_ = 1 * 1024*1024;
354   char* stack_;
355   bool pc_modified_;
356   int icount_;
357   int break_count_;
358
359   // Debugger input.
360   char* last_debugger_input_;
361
362   // Icache simulation.
363   v8::internal::HashMap* i_cache_;
364
365   v8::internal::Isolate* isolate_;
366
367   // Registered breakpoints.
368   Instruction* break_pc_;
369   Instr break_instr_;
370
371   // Stop is disabled if bit 31 is set.
372   static const uint32_t kStopDisabledBit = 1 << 31;
373
374   // A stop is enabled, meaning the simulator will stop when meeting the
375   // instruction, if bit 31 of watched_stops_[code].count is unset.
376   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
377   // the breakpoint was hit or gone through.
378   struct StopCountAndDesc {
379     uint32_t count;
380     char* desc;
381   };
382   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
383 };
384
385
386 // When running with the simulator transition into simulated execution at this
387 // point.
388 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
389     reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
390       FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
391
392 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
393     Simulator::current(Isolate::Current())->Call( \
394         entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
395
396
397 // The simulator has its own stack. Thus it has a different stack limit from
398 // the C-based native code.  Setting the c_limit to indicate a very small
399 // stack cause stack overflow errors, since the simulator ignores the input.
400 // This is unlikely to be an issue in practice, though it might cause testing
401 // trouble down the line.
402 class SimulatorStack : public v8::internal::AllStatic {
403  public:
404   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
405                                             uintptr_t c_limit) {
406     return Simulator::current(isolate)->StackLimit();
407   }
408
409   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
410     Simulator* sim = Simulator::current(Isolate::Current());
411     return sim->PushAddress(try_catch_address);
412   }
413
414   static inline void UnregisterCTryCatch() {
415     Simulator::current(Isolate::Current())->PopAddress();
416   }
417 };
418
419 } }  // namespace v8::internal
420
421 #endif  // !defined(USE_SIMULATOR)
422 #endif  // V8_MIPS_SIMULATOR_MIPS_H_