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