V8 Project
simulator-mips.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 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.
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,
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,
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_
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
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