[presubmit] Enable readability/namespace linter checking.
[platform/upstream/v8.git] / src / mips64 / simulator-mips64.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/mips64/constants-mips64.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
30 // Call the generated regexp code directly. The code at the entry address
31 // should act as a function matching the type arm_regexp_matcher.
32 // The fifth (or ninth) argument is a dummy that reserves the space used for
33 // the return address added by the ExitFrame in native calls.
34 #ifdef MIPS_ABI_N64
35 typedef int (*mips_regexp_matcher)(String* input,
36                                    int64_t start_offset,
37                                    const byte* input_start,
38                                    const byte* input_end,
39                                    int* output,
40                                    int64_t output_size,
41                                    Address stack_base,
42                                    int64_t direct_call,
43                                    void* return_address,
44                                    Isolate* isolate);
45
46 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
47   (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
48       p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))
49
50 #else  // O32 Abi.
51
52 typedef int (*mips_regexp_matcher)(String* input,
53                                    int32_t start_offset,
54                                    const byte* input_start,
55                                    const byte* input_end,
56                                    void* return_address,
57                                    int* output,
58                                    int32_t output_size,
59                                    Address stack_base,
60                                    int32_t direct_call,
61                                    Isolate* isolate);
62
63 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
64   (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
65       p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
66
67 #endif  // MIPS_ABI_N64
68
69
70 // The stack limit beyond which we will throw stack overflow errors in
71 // generated code. Because generated code on mips uses the C stack, we
72 // just use the C stack limit.
73 class SimulatorStack : public v8::internal::AllStatic {
74  public:
75   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
76                                             uintptr_t c_limit) {
77     return c_limit;
78   }
79
80   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
81     return try_catch_address;
82   }
83
84   static inline void UnregisterCTryCatch() { }
85 };
86
87 }  // namespace internal
88 }  // namespace v8
89
90 // Calculated the stack limit beyond which we will throw stack overflow errors.
91 // This macro must be called from a C++ method. It relies on being able to take
92 // the address of "this" to get a value on the current execution stack and then
93 // calculates the stack limit based on that value.
94 // NOTE: The check for overflow is not safe as there is no guarantee that the
95 // running thread has its stack in all memory up to address 0x00000000.
96 #define GENERATED_CODE_STACK_LIMIT(limit) \
97   (reinterpret_cast<uintptr_t>(this) >= limit ? \
98       reinterpret_cast<uintptr_t>(this) - limit : 0)
99
100 #else  // !defined(USE_SIMULATOR)
101 // Running with a simulator.
102
103 #include "src/assembler.h"
104 #include "src/hashmap.h"
105
106 namespace v8 {
107 namespace internal {
108
109 // -----------------------------------------------------------------------------
110 // Utility functions
111
112 class CachePage {
113  public:
114   static const int LINE_VALID = 0;
115   static const int LINE_INVALID = 1;
116
117   static const int kPageShift = 12;
118   static const int kPageSize = 1 << kPageShift;
119   static const int kPageMask = kPageSize - 1;
120   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
121   static const int kLineLength = 1 << kLineShift;
122   static const int kLineMask = kLineLength - 1;
123
124   CachePage() {
125     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
126   }
127
128   char* ValidityByte(int offset) {
129     return &validity_map_[offset >> kLineShift];
130   }
131
132   char* CachedData(int offset) {
133     return &data_[offset];
134   }
135
136  private:
137   char data_[kPageSize];   // The cached data.
138   static const int kValidityMapSize = kPageSize >> kLineShift;
139   char validity_map_[kValidityMapSize];  // One byte per line.
140 };
141
142 class Simulator {
143  public:
144   friend class MipsDebugger;
145
146   // Registers are declared in order. See SMRL chapter 2.
147   enum Register {
148     no_reg = -1,
149     zero_reg = 0,
150     at,
151     v0, v1,
152     a0, a1, a2, a3, a4, a5, a6, a7,
153     t0, t1, t2, t3,
154     s0, s1, s2, s3, s4, s5, s6, s7,
155     t8, t9,
156     k0, k1,
157     gp,
158     sp,
159     s8,
160     ra,
161     // LO, HI, and pc.
162     LO,
163     HI,
164     pc,   // pc must be the last register.
165     kNumSimuRegisters,
166     // aliases
167     fp = s8
168   };
169
170   // Coprocessor registers.
171   // Generated code will always use doubles. So we will only use even registers.
172   enum FPURegister {
173     f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
174     f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
175     f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
176     f26, f27, f28, f29, f30, f31,
177     kNumFPURegisters
178   };
179
180   explicit Simulator(Isolate* isolate);
181   ~Simulator();
182
183   // The currently executing Simulator instance. Potentially there can be one
184   // for each native thread.
185   static Simulator* current(v8::internal::Isolate* isolate);
186
187   // Accessors for register state. Reading the pc value adheres to the MIPS
188   // architecture specification and is off by a 8 from the currently executing
189   // instruction.
190   void set_register(int reg, int64_t value);
191   void set_register_word(int reg, int32_t value);
192   void set_dw_register(int dreg, const int* dbl);
193   int64_t get_register(int reg) const;
194   double get_double_from_register_pair(int reg);
195   // Same for FPURegisters.
196   void set_fpu_register(int fpureg, int64_t value);
197   void set_fpu_register_word(int fpureg, int32_t value);
198   void set_fpu_register_hi_word(int fpureg, int32_t value);
199   void set_fpu_register_float(int fpureg, float value);
200   void set_fpu_register_double(int fpureg, double value);
201   int64_t get_fpu_register(int fpureg) const;
202   int32_t get_fpu_register_word(int fpureg) const;
203   int32_t get_fpu_register_signed_word(int fpureg) const;
204   int32_t get_fpu_register_hi_word(int fpureg) const;
205   float get_fpu_register_float(int fpureg) const;
206   double get_fpu_register_double(int fpureg) const;
207   void set_fcsr_bit(uint32_t cc, bool value);
208   bool test_fcsr_bit(uint32_t cc);
209   bool set_fcsr_round_error(double original, double rounded);
210   bool set_fcsr_round64_error(double original, double rounded);
211   bool set_fcsr_round_error(float original, float rounded);
212   bool set_fcsr_round64_error(float original, float rounded);
213   void round_according_to_fcsr(double toRound, double& rounded,
214                                int32_t& rounded_int, double fs);
215   void round64_according_to_fcsr(double toRound, double& rounded,
216                                  int64_t& rounded_int, double fs);
217   void round_according_to_fcsr(float toRound, float& rounded,
218                                int32_t& rounded_int, float fs);
219   void round64_according_to_fcsr(float toRound, float& rounded,
220                                  int64_t& rounded_int, float fs);
221   void set_fcsr_rounding_mode(FPURoundingMode mode);
222   unsigned int get_fcsr_rounding_mode();
223   // Special case of set_register and get_register to access the raw PC value.
224   void set_pc(int64_t value);
225   int64_t get_pc() const;
226
227   Address get_sp() const {
228     return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
229   }
230
231   // Accessor to the internal simulator stack area.
232   uintptr_t StackLimit(uintptr_t c_limit) const;
233
234   // Executes MIPS instructions until the PC reaches end_sim_pc.
235   void Execute();
236
237   // Call on program start.
238   static void Initialize(Isolate* isolate);
239
240   static void TearDown(HashMap* i_cache, Redirection* first);
241
242   // V8 generally calls into generated JS code with 5 parameters and into
243   // generated RegExp code with 7 parameters. This is a convenience function,
244   // which sets up the simulator state and grabs the result on return.
245   int64_t Call(byte* entry, int argument_count, ...);
246   // Alternative: call a 2-argument double function.
247   double CallFP(byte* entry, double d0, double d1);
248
249   // Push an address onto the JS stack.
250   uintptr_t PushAddress(uintptr_t address);
251
252   // Pop an address from the JS stack.
253   uintptr_t PopAddress();
254
255   // Debugger input.
256   void set_last_debugger_input(char* input);
257   char* last_debugger_input() { return last_debugger_input_; }
258
259   // ICache checking.
260   static void FlushICache(v8::internal::HashMap* i_cache, void* start,
261                           size_t size);
262
263   // Returns true if pc register contains one of the 'special_values' defined
264   // below (bad_ra, end_sim_pc).
265   bool has_bad_pc() const;
266
267  private:
268   enum special_values {
269     // Known bad pc value to ensure that the simulator does not execute
270     // without being properly setup.
271     bad_ra = -1,
272     // A pc value used to signal the simulator to stop execution.  Generally
273     // the ra is set to this value on transition from native C code to
274     // simulated execution, so that the simulator can "return" to the native
275     // C code.
276     end_sim_pc = -2,
277     // Unpredictable value.
278     Unpredictable = 0xbadbeaf
279   };
280
281   // Unsupported instructions use Format to print an error and stop execution.
282   void Format(Instruction* instr, const char* format);
283
284   // Read and write memory.
285   inline uint32_t ReadBU(int64_t addr);
286   inline int32_t ReadB(int64_t addr);
287   inline void WriteB(int64_t addr, uint8_t value);
288   inline void WriteB(int64_t addr, int8_t value);
289
290   inline uint16_t ReadHU(int64_t addr, Instruction* instr);
291   inline int16_t ReadH(int64_t addr, Instruction* instr);
292   // Note: Overloaded on the sign of the value.
293   inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
294   inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
295
296   inline uint32_t ReadWU(int64_t addr, Instruction* instr);
297   inline int32_t ReadW(int64_t addr, Instruction* instr);
298   inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
299   inline int64_t Read2W(int64_t addr, Instruction* instr);
300   inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
301
302   inline double ReadD(int64_t addr, Instruction* instr);
303   inline void WriteD(int64_t addr, double value, Instruction* instr);
304
305   // Helper for debugging memory access.
306   inline void DieOrDebug();
307
308   // Helpers for data value tracing.
309     enum TraceType {
310     BYTE,
311     HALF,
312     WORD,
313     DWORD
314     // DFLOAT - Floats may have printing issues due to paired lwc1's
315   };
316
317   void TraceRegWr(int64_t value);
318   void TraceMemWr(int64_t addr, int64_t value, TraceType t);
319   void TraceMemRd(int64_t addr, int64_t value);
320
321   // Operations depending on endianness.
322   // Get Double Higher / Lower word.
323   inline int32_t GetDoubleHIW(double* addr);
324   inline int32_t GetDoubleLOW(double* addr);
325   // Set Double Higher / Lower word.
326   inline int32_t SetDoubleHIW(double* addr);
327   inline int32_t SetDoubleLOW(double* addr);
328
329   // functions called from DecodeTypeRegister.
330   void DecodeTypeRegisterCOP1();
331
332   void DecodeTypeRegisterCOP1X();
333
334   void DecodeTypeRegisterSPECIAL();
335
336
337   void DecodeTypeRegisterSPECIAL2();
338
339   void DecodeTypeRegisterSPECIAL3();
340
341   void DecodeTypeRegisterSRsType();
342
343   void DecodeTypeRegisterDRsType();
344
345   void DecodeTypeRegisterWRsType();
346
347   void DecodeTypeRegisterLRsType();
348
349   // Executing is handled based on the instruction type.
350   void DecodeTypeRegister(Instruction* instr);
351
352   Instruction* currentInstr_;
353   inline Instruction* get_instr() const { return currentInstr_; }
354   inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
355
356   inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
357   inline int64_t rs() const { return get_register(rs_reg()); }
358   inline uint64_t rs_u() const {
359     return static_cast<uint64_t>(get_register(rs_reg()));
360   }
361   inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
362   inline int64_t rt() const { return get_register(rt_reg()); }
363   inline uint64_t rt_u() const {
364     return static_cast<uint64_t>(get_register(rt_reg()));
365   }
366   inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
367   inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
368   inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
369   inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
370   inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
371   inline int32_t sa() const { return currentInstr_->SaValue(); }
372
373   inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
374     set_register(rd_reg, alu_out);
375     TraceRegWr(alu_out);
376   }
377
378   void DecodeTypeImmediate(Instruction* instr);
379   void DecodeTypeJump(Instruction* instr);
380
381   // Used for breakpoints and traps.
382   void SoftwareInterrupt(Instruction* instr);
383
384   // Stop helper functions.
385   bool IsWatchpoint(uint64_t code);
386   void PrintWatchpoint(uint64_t code);
387   void HandleStop(uint64_t code, Instruction* instr);
388   bool IsStopInstruction(Instruction* instr);
389   bool IsEnabledStop(uint64_t code);
390   void EnableStop(uint64_t code);
391   void DisableStop(uint64_t code);
392   void IncreaseStopCounter(uint64_t code);
393   void PrintStopInfo(uint64_t code);
394
395
396   // Executes one instruction.
397   void InstructionDecode(Instruction* instr);
398   // Execute one instruction placed in a branch delay slot.
399   void BranchDelayInstructionDecode(Instruction* instr) {
400     if (instr->InstructionBits() == nopInstr) {
401       // Short-cut generic nop instructions. They are always valid and they
402       // never change the simulator state.
403       return;
404     }
405
406     if (instr->IsForbiddenInBranchDelay()) {
407       V8_Fatal(__FILE__, __LINE__,
408                "Eror:Unexpected %i opcode in a branch delay slot.",
409                instr->OpcodeValue());
410     }
411     InstructionDecode(instr);
412     SNPrintF(trace_buf_, " ");
413   }
414
415   // ICache.
416   static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
417   static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
418                            size_t size);
419   static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
420
421   enum Exception {
422     none,
423     kIntegerOverflow,
424     kIntegerUnderflow,
425     kDivideByZero,
426     kNumExceptions
427   };
428
429   // Exceptions.
430   void SignalException(Exception e);
431
432   // Runtime call support.
433   static void* RedirectExternalReference(void* external_function,
434                                          ExternalReference::Type type);
435
436   // Handle arguments and return value for runtime FP functions.
437   void GetFpArgs(double* x, double* y, int32_t* z);
438   void SetFpResult(const double& result);
439
440   void CallInternal(byte* entry);
441
442   // Architecture state.
443   // Registers.
444   int64_t registers_[kNumSimuRegisters];
445   // Coprocessor Registers.
446   int64_t FPUregisters_[kNumFPURegisters];
447   // FPU control register.
448   uint32_t FCSR_;
449
450   // Simulator support.
451   // Allocate 1MB for stack.
452   size_t stack_size_;
453   char* stack_;
454   bool pc_modified_;
455   int64_t icount_;
456   int break_count_;
457   EmbeddedVector<char, 128> trace_buf_;
458
459   // Debugger input.
460   char* last_debugger_input_;
461
462   // Icache simulation.
463   v8::internal::HashMap* i_cache_;
464
465   v8::internal::Isolate* isolate_;
466
467   // Registered breakpoints.
468   Instruction* break_pc_;
469   Instr break_instr_;
470
471   // Stop is disabled if bit 31 is set.
472   static const uint32_t kStopDisabledBit = 1 << 31;
473
474   // A stop is enabled, meaning the simulator will stop when meeting the
475   // instruction, if bit 31 of watched_stops_[code].count is unset.
476   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
477   // the breakpoint was hit or gone through.
478   struct StopCountAndDesc {
479     uint32_t count;
480     char* desc;
481   };
482   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
483 };
484
485
486 // When running with the simulator transition into simulated execution at this
487 // point.
488 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4)                    \
489   reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
490       FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0),            \
491       reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2),     \
492       reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
493
494
495 #ifdef MIPS_ABI_N64
496 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
497   static_cast<int>(Simulator::current(Isolate::Current())                     \
498                        ->Call(entry, 10, p0, p1, p2, p3, p4,                  \
499                               reinterpret_cast<int64_t*>(p5), p6, p7, NULL,   \
500                               p8))
501 #else  // Must be O32 Abi.
502 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
503   static_cast<int>(                                                           \
504       Simulator::current(Isolate::Current())                                  \
505           ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
506 #endif  // MIPS_ABI_N64
507
508
509 // The simulator has its own stack. Thus it has a different stack limit from
510 // the C-based native code.  The JS-based limit normally points near the end of
511 // the simulator stack.  When the C-based limit is exhausted we reflect that by
512 // lowering the JS-based limit as well, to make stack checks trigger.
513 class SimulatorStack : public v8::internal::AllStatic {
514  public:
515   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
516                                             uintptr_t c_limit) {
517     return Simulator::current(isolate)->StackLimit(c_limit);
518   }
519
520   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
521     Simulator* sim = Simulator::current(Isolate::Current());
522     return sim->PushAddress(try_catch_address);
523   }
524
525   static inline void UnregisterCTryCatch() {
526     Simulator::current(Isolate::Current())->PopAddress();
527   }
528 };
529
530 }  // namespace internal
531 }  // namespace v8
532
533 #endif  // !defined(USE_SIMULATOR)
534 #endif  // V8_MIPS_SIMULATOR_MIPS_H_