v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
simulator-mips.h
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 
29 // Declares a Simulator for MIPS instructions if we are not generating a native
30 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
31 // on regular desktop machines.
32 // V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
33 // which will start execution in the Simulator or forwards to the real entry
34 // on a MIPS HW platform.
35 
36 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
37 #define V8_MIPS_SIMULATOR_MIPS_H_
38 
39 #include "allocation.h"
40 #include "constants-mips.h"
41 
42 #if !defined(USE_SIMULATOR)
43 // Running without a simulator on a native mips platform.
44 
45 namespace v8 {
46 namespace internal {
47 
48 // When running without a simulator we call the entry directly.
49 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
50  entry(p0, p1, p2, p3, p4)
51 
52 typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
53  void*, int*, int, Address, int, Isolate*);
54 
55 
56 // Call the generated regexp code directly. The code at the entry address
57 // should act as a function matching the type arm_regexp_matcher.
58 // The fifth argument is a dummy that reserves the space used for
59 // the return address added by the ExitFrame in native calls.
60 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
61  (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
62  p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
63 
64 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
65  reinterpret_cast<TryCatch*>(try_catch_address)
66 
67 // The stack limit beyond which we will throw stack overflow errors in
68 // generated code. Because generated code on mips uses the C stack, we
69 // just use the C stack limit.
70 class SimulatorStack : public v8::internal::AllStatic {
71  public:
72  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
73  uintptr_t c_limit) {
74  return c_limit;
75  }
76 
77  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
78  return try_catch_address;
79  }
80 
81  static inline void UnregisterCTryCatch() { }
82 };
83 
84 } } // namespace v8::internal
85 
86 // Calculated the stack limit beyond which we will throw stack overflow errors.
87 // This macro must be called from a C++ method. It relies on being able to take
88 // the address of "this" to get a value on the current execution stack and then
89 // calculates the stack limit based on that value.
90 // NOTE: The check for overflow is not safe as there is no guarantee that the
91 // running thread has its stack in all memory up to address 0x00000000.
92 #define GENERATED_CODE_STACK_LIMIT(limit) \
93  (reinterpret_cast<uintptr_t>(this) >= limit ? \
94  reinterpret_cast<uintptr_t>(this) - limit : 0)
95 
96 #else // !defined(USE_SIMULATOR)
97 // Running with a simulator.
98 
99 #include "hashmap.h"
100 #include "assembler.h"
101 
102 namespace v8 {
103 namespace internal {
104 
105 // -----------------------------------------------------------------------------
106 // Utility functions
107 
108 class CachePage {
109  public:
110  static const int LINE_VALID = 0;
111  static const int LINE_INVALID = 1;
112 
113  static const int kPageShift = 12;
114  static const int kPageSize = 1 << kPageShift;
115  static const int kPageMask = kPageSize - 1;
116  static const int kLineShift = 2; // The cache line is only 4 bytes right now.
117  static const int kLineLength = 1 << kLineShift;
118  static const int kLineMask = kLineLength - 1;
119 
120  CachePage() {
121  memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
122  }
123 
124  char* ValidityByte(int offset) {
125  return &validity_map_[offset >> kLineShift];
126  }
127 
128  char* CachedData(int offset) {
129  return &data_[offset];
130  }
131 
132  private:
133  char data_[kPageSize]; // The cached data.
134  static const int kValidityMapSize = kPageSize >> kLineShift;
135  char validity_map_[kValidityMapSize]; // One byte per line.
136 };
137 
138 class Simulator {
139  public:
140  friend class MipsDebugger;
141 
142  // Registers are declared in order. See SMRL chapter 2.
143  enum Register {
144  no_reg = -1,
145  zero_reg = 0,
146  at,
147  v0, v1,
148  a0, a1, a2, a3,
149  t0, t1, t2, t3, t4, t5, t6, t7,
150  s0, s1, s2, s3, s4, s5, s6, s7,
151  t8, t9,
152  k0, k1,
153  gp,
154  sp,
155  s8,
156  ra,
157  // LO, HI, and pc.
158  LO,
159  HI,
160  pc, // pc must be the last register.
162  // aliases
163  fp = s8
164  };
165 
166  // Coprocessor registers.
167  // Generated code will always use doubles. So we will only use even registers.
168  enum FPURegister {
169  f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
170  f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
171  f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
172  f26, f27, f28, f29, f30, f31,
174  };
175 
176  explicit Simulator(Isolate* isolate);
177  ~Simulator();
178 
179  // The currently executing Simulator instance. Potentially there can be one
180  // for each native thread.
181  static Simulator* current(v8::internal::Isolate* isolate);
182 
183  // Accessors for register state. Reading the pc value adheres to the MIPS
184  // architecture specification and is off by a 8 from the currently executing
185  // instruction.
186  void set_register(int reg, int32_t value);
187  int32_t get_register(int reg) const;
188  // Same for FPURegisters.
189  void set_fpu_register(int fpureg, int32_t value);
190  void set_fpu_register_float(int fpureg, float value);
191  void set_fpu_register_double(int fpureg, double value);
192  int32_t get_fpu_register(int fpureg) const;
193  int64_t get_fpu_register_long(int fpureg) const;
194  float get_fpu_register_float(int fpureg) const;
195  double get_fpu_register_double(int fpureg) const;
196  void set_fcsr_bit(uint32_t cc, bool value);
197  bool test_fcsr_bit(uint32_t cc);
198  bool set_fcsr_round_error(double original, double rounded);
199 
200  // Special case of set_register and get_register to access the raw PC value.
201  void set_pc(int32_t value);
202  int32_t get_pc() const;
203 
204  // Accessor to the internal simulator stack area.
205  uintptr_t StackLimit() const;
206 
207  // Executes MIPS instructions until the PC reaches end_sim_pc.
208  void Execute();
209 
210  // Call on program start.
211  static void Initialize(Isolate* isolate);
212 
213  // V8 generally calls into generated JS code with 5 parameters and into
214  // generated RegExp code with 7 parameters. This is a convenience function,
215  // which sets up the simulator state and grabs the result on return.
216  int32_t Call(byte* entry, int argument_count, ...);
217 
218  // Push an address onto the JS stack.
219  uintptr_t PushAddress(uintptr_t address);
220 
221  // Pop an address from the JS stack.
222  uintptr_t PopAddress();
223 
224  // Debugger input.
225  void set_last_debugger_input(char* input);
226  char* last_debugger_input() { return last_debugger_input_; }
227 
228  // ICache checking.
229  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
230  size_t size);
231 
232  // Returns true if pc register contains one of the 'special_values' defined
233  // below (bad_ra, end_sim_pc).
234  bool has_bad_pc() const;
235 
236  private:
237  enum special_values {
238  // Known bad pc value to ensure that the simulator does not execute
239  // without being properly setup.
240  bad_ra = -1,
241  // A pc value used to signal the simulator to stop execution. Generally
242  // the ra is set to this value on transition from native C code to
243  // simulated execution, so that the simulator can "return" to the native
244  // C code.
245  end_sim_pc = -2,
246  // Unpredictable value.
247  Unpredictable = 0xbadbeaf
248  };
249 
250  // Unsupported instructions use Format to print an error and stop execution.
251  void Format(Instruction* instr, const char* format);
252 
253  // Read and write memory.
254  inline uint32_t ReadBU(int32_t addr);
255  inline int32_t ReadB(int32_t addr);
256  inline void WriteB(int32_t addr, uint8_t value);
257  inline void WriteB(int32_t addr, int8_t value);
258 
259  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
260  inline int16_t ReadH(int32_t addr, Instruction* instr);
261  // Note: Overloaded on the sign of the value.
262  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
263  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
264 
265  inline int ReadW(int32_t addr, Instruction* instr);
266  inline void WriteW(int32_t addr, int value, Instruction* instr);
267 
268  inline double ReadD(int32_t addr, Instruction* instr);
269  inline void WriteD(int32_t addr, double value, Instruction* instr);
270 
271  // Operations depending on endianness.
272  // Get Double Higher / Lower word.
273  inline int32_t GetDoubleHIW(double* addr);
274  inline int32_t GetDoubleLOW(double* addr);
275  // Set Double Higher / Lower word.
276  inline int32_t SetDoubleHIW(double* addr);
277  inline int32_t SetDoubleLOW(double* addr);
278 
279  // Executing is handled based on the instruction type.
280  void DecodeTypeRegister(Instruction* instr);
281 
282  // Helper function for DecodeTypeRegister.
283  void ConfigureTypeRegister(Instruction* instr,
284  int32_t& alu_out,
285  int64_t& i64hilo,
286  uint64_t& u64hilo,
287  int32_t& next_pc,
288  bool& do_interrupt);
289 
290  void DecodeTypeImmediate(Instruction* instr);
291  void DecodeTypeJump(Instruction* instr);
292 
293  // Used for breakpoints and traps.
294  void SoftwareInterrupt(Instruction* instr);
295 
296  // Stop helper functions.
297  bool IsWatchpoint(uint32_t code);
298  void PrintWatchpoint(uint32_t code);
299  void HandleStop(uint32_t code, Instruction* instr);
300  bool IsStopInstruction(Instruction* instr);
301  bool IsEnabledStop(uint32_t code);
302  void EnableStop(uint32_t code);
303  void DisableStop(uint32_t code);
304  void IncreaseStopCounter(uint32_t code);
305  void PrintStopInfo(uint32_t code);
306 
307 
308  // Executes one instruction.
309  void InstructionDecode(Instruction* instr);
310  // Execute one instruction placed in a branch delay slot.
311  void BranchDelayInstructionDecode(Instruction* instr) {
312  if (instr->InstructionBits() == nopInstr) {
313  // Short-cut generic nop instructions. They are always valid and they
314  // never change the simulator state.
315  set_register(pc, reinterpret_cast<int32_t>(instr) +
317  return;
318  }
319 
320  if (instr->IsForbiddenInBranchDelay()) {
321  V8_Fatal(__FILE__, __LINE__,
322  "Eror:Unexpected %i opcode in a branch delay slot.",
323  instr->OpcodeValue());
324  }
325  InstructionDecode(instr);
326  }
327 
328  // ICache.
329  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
330  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
331  int size);
332  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
333 
334  enum Exception {
335  none,
336  kIntegerOverflow,
337  kIntegerUnderflow,
338  kDivideByZero,
339  kNumExceptions
340  };
341  int16_t exceptions[kNumExceptions];
342 
343  // Exceptions.
344  void SignalExceptions();
345 
346  // Runtime call support.
347  static void* RedirectExternalReference(void* external_function,
348  ExternalReference::Type type);
349 
350  // For use in calls that take double value arguments.
351  void GetFpArgs(double* x, double* y);
352  void GetFpArgs(double* x);
353  void GetFpArgs(double* x, int32_t* y);
354  void SetFpResult(const double& result);
355 
356 
357  // Architecture state.
358  // Registers.
359  int32_t registers_[kNumSimuRegisters];
360  // Coprocessor Registers.
361  int32_t FPUregisters_[kNumFPURegisters];
362  // FPU control register.
363  uint32_t FCSR_;
364 
365  // Simulator support.
366  // Allocate 1MB for stack.
367  static const size_t stack_size_ = 1 * 1024*1024;
368  char* stack_;
369  bool pc_modified_;
370  int icount_;
371  int break_count_;
372 
373  // Debugger input.
374  char* last_debugger_input_;
375 
376  // Icache simulation.
377  v8::internal::HashMap* i_cache_;
378 
379  v8::internal::Isolate* isolate_;
380 
381  // Registered breakpoints.
382  Instruction* break_pc_;
383  Instr break_instr_;
384 
385  // Stop is disabled if bit 31 is set.
386  static const uint32_t kStopDisabledBit = 1 << 31;
387 
388  // A stop is enabled, meaning the simulator will stop when meeting the
389  // instruction, if bit 31 of watched_stops[code].count is unset.
390  // The value watched_stops[code].count & ~(1 << 31) indicates how many times
391  // the breakpoint was hit or gone through.
392  struct StopCountAndDesc {
393  uint32_t count;
394  char* desc;
395  };
396  StopCountAndDesc watched_stops[kMaxStopCode + 1];
397 };
398 
399 
400 // When running with the simulator transition into simulated execution at this
401 // point.
402 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
403  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
404  FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
405 
406 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
407  Simulator::current(Isolate::Current())->Call( \
408  entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
409 
410 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
411  try_catch_address == NULL ? \
412  NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
413 
414 
415 // The simulator has its own stack. Thus it has a different stack limit from
416 // the C-based native code. Setting the c_limit to indicate a very small
417 // stack cause stack overflow errors, since the simulator ignores the input.
418 // This is unlikely to be an issue in practice, though it might cause testing
419 // trouble down the line.
420 class SimulatorStack : public v8::internal::AllStatic {
421  public:
422  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
423  uintptr_t c_limit) {
424  return Simulator::current(isolate)->StackLimit();
425  }
426 
427  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
428  Simulator* sim = Simulator::current(Isolate::Current());
429  return sim->PushAddress(try_catch_address);
430  }
431 
432  static inline void UnregisterCTryCatch() {
433  Simulator::current(Isolate::Current())->PopAddress();
434  }
435 };
436 
437 } } // namespace v8::internal
438 
439 #endif // !defined(USE_SIMULATOR)
440 #endif // V8_MIPS_SIMULATOR_MIPS_H_
byte * Address
Definition: globals.h:172
const FPURegister f4
const SwVfpRegister s2
const FPURegister f20
const FPURegister f21
const FPURegister f28
const FPURegister f5
const FPURegister f15
const FPURegister f11
const SwVfpRegister s7
const SwVfpRegister s8
const FPURegister f0
static uintptr_t JsLimitFromCLimit(Isolate *isolate, uintptr_t c_limit)
const FPURegister f24
const FPURegister f22
const FPURegister f10
const int kNumSimuRegisters
const FPURegister f18
int(* mips_regexp_matcher)(String *, int, const byte *, const byte *, void *, int *, int, Address, int, Isolate *)
int int32_t
Definition: unicode.cc:47
const uint32_t kMaxStopCode
unsigned short uint16_t
Definition: unicode.cc:46
const FPURegister f3
const Instr nopInstr
const SwVfpRegister s6
const int kNumFPURegisters
uint8_t byte
Definition: globals.h:171
const Register sp
const SwVfpRegister s3
void V8_Fatal(const char *file, int line, const char *format,...)
Definition: checks.cc:38
const FPURegister f16
const FPURegister f9
const FPURegister f29
static uintptr_t JsLimitFromCLimit(v8::internal::Isolate *isolate, uintptr_t c_limit)
Definition: simulator-arm.h:71
const FPURegister f17
const FPURegister f23
const Register pc
const SwVfpRegister s0
const FPURegister f2
const SwVfpRegister s5
const SwVfpRegister s1
const FPURegister f19
const FPURegister f30
const FPURegister f27
const FPURegister f1
const FPURegister f7
const SwVfpRegister s4
const FPURegister f12
const FPURegister f6
const Register no_reg
static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address)
const Register fp
signed short int16_t
Definition: unicode.cc:45
const FPURegister f14
const FPURegister f31
FlagType type() const
Definition: flags.cc:1358
const FPURegister f25
const FPURegister f26
const FPURegister f13
const FPURegister f8