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