V8 Project
simulator-arm.h
Go to the documentation of this file.
1 // Copyright 2012 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 ARM instructions if we are not generating a native
7 // ARM binary. This Simulator allows us to run and debug ARM code generation on
8 // 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 ARM HW platform.
12 
13 #ifndef V8_ARM_SIMULATOR_ARM_H_
14 #define V8_ARM_SIMULATOR_ARM_H_
15 
16 #include "src/allocation.h"
17 
18 #if !defined(USE_SIMULATOR)
19 // Running without a simulator on a native arm platform.
20 
21 namespace v8 {
22 namespace internal {
23 
24 // When running without a simulator we call the entry directly.
25 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
26  (entry(p0, p1, p2, p3, p4))
27 
28 typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*,
29  void*, int*, int, Address, int, Isolate*);
30 
31 
32 // Call the generated regexp code directly. The code at the entry address
33 // should act as a function matching the type arm_regexp_matcher.
34 // The fifth argument is a dummy that reserves the space used for
35 // the return address added by the ExitFrame in native calls.
36 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
37  (FUNCTION_CAST<arm_regexp_matcher>(entry)( \
38  p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
39 
40 // The stack limit beyond which we will throw stack overflow errors in
41 // generated code. Because generated code on arm uses the C stack, we
42 // just use the C stack limit.
44  public:
46  uintptr_t c_limit) {
47  USE(isolate);
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 #else // !defined(USE_SIMULATOR)
61 // Running with a simulator.
62 
63 #include "src/arm/constants-arm.h"
64 #include "src/assembler.h"
65 #include "src/hashmap.h"
66 
67 namespace v8 {
68 namespace internal {
69 
70 class CachePage {
71  public:
72  static const int LINE_VALID = 0;
73  static const int LINE_INVALID = 1;
74 
75  static const int kPageShift = 12;
76  static const int kPageSize = 1 << kPageShift;
77  static const int kPageMask = kPageSize - 1;
78  static const int kLineShift = 2; // The cache line is only 4 bytes right now.
79  static const int kLineLength = 1 << kLineShift;
80  static const int kLineMask = kLineLength - 1;
81 
82  CachePage() {
83  memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
84  }
85 
86  char* ValidityByte(int offset) {
87  return &validity_map_[offset >> kLineShift];
88  }
89 
90  char* CachedData(int offset) {
91  return &data_[offset];
92  }
93 
94  private:
95  char data_[kPageSize]; // The cached data.
96  static const int kValidityMapSize = kPageSize >> kLineShift;
97  char validity_map_[kValidityMapSize]; // One byte per line.
98 };
99 
100 
101 class Simulator {
102  public:
103  friend class ArmDebugger;
104  enum Register {
105  no_reg = -1,
106  r0 = 0, r1, r2, r3, r4, r5, r6, r7,
107  r8, r9, r10, r11, r12, r13, r14, r15,
108  num_registers,
109  sp = 13,
110  lr = 14,
111  pc = 15,
112  s0 = 0, s1, s2, s3, s4, s5, s6, s7,
113  s8, s9, s10, s11, s12, s13, s14, s15,
114  s16, s17, s18, s19, s20, s21, s22, s23,
115  s24, s25, s26, s27, s28, s29, s30, s31,
116  num_s_registers = 32,
117  d0 = 0, d1, d2, d3, d4, d5, d6, d7,
118  d8, d9, d10, d11, d12, d13, d14, d15,
119  d16, d17, d18, d19, d20, d21, d22, d23,
120  d24, d25, d26, d27, d28, d29, d30, d31,
121  num_d_registers = 32,
122  q0 = 0, q1, q2, q3, q4, q5, q6, q7,
123  q8, q9, q10, q11, q12, q13, q14, q15,
124  num_q_registers = 16
125  };
126 
127  explicit Simulator(Isolate* isolate);
128  ~Simulator();
129 
130  // The currently executing Simulator instance. Potentially there can be one
131  // for each native thread.
132  static Simulator* current(v8::internal::Isolate* isolate);
133 
134  // Accessors for register state. Reading the pc value adheres to the ARM
135  // architecture specification and is off by a 8 from the currently executing
136  // instruction.
137  void set_register(int reg, int32_t value);
138  int32_t get_register(int reg) const;
139  double get_double_from_register_pair(int reg);
140  void set_register_pair_from_double(int reg, double* value);
141  void set_dw_register(int dreg, const int* dbl);
142 
143  // Support for VFP.
144  void get_d_register(int dreg, uint64_t* value);
145  void set_d_register(int dreg, const uint64_t* value);
146  void get_d_register(int dreg, uint32_t* value);
147  void set_d_register(int dreg, const uint32_t* value);
148  void get_q_register(int qreg, uint64_t* value);
149  void set_q_register(int qreg, const uint64_t* value);
150  void get_q_register(int qreg, uint32_t* value);
151  void set_q_register(int qreg, const uint32_t* value);
152 
153  void set_s_register(int reg, unsigned int value);
154  unsigned int get_s_register(int reg) const;
155 
156  void set_d_register_from_double(int dreg, const double& dbl) {
157  SetVFPRegister<double, 2>(dreg, dbl);
158  }
159 
160  double get_double_from_d_register(int dreg) {
161  return GetFromVFPRegister<double, 2>(dreg);
162  }
163 
164  void set_s_register_from_float(int sreg, const float flt) {
165  SetVFPRegister<float, 1>(sreg, flt);
166  }
167 
168  float get_float_from_s_register(int sreg) {
169  return GetFromVFPRegister<float, 1>(sreg);
170  }
171 
172  void set_s_register_from_sinteger(int sreg, const int sint) {
173  SetVFPRegister<int, 1>(sreg, sint);
174  }
175 
176  int get_sinteger_from_s_register(int sreg) {
177  return GetFromVFPRegister<int, 1>(sreg);
178  }
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 ARM 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  void CallFP(byte* entry, double d0, double d1);
203  int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
204  double CallFPReturnsDouble(byte* entry, double d0, double d1);
205 
206  // Push an address onto the JS stack.
207  uintptr_t PushAddress(uintptr_t address);
208 
209  // Pop an address from the JS stack.
210  uintptr_t PopAddress();
211 
212  // Debugger input.
213  void set_last_debugger_input(char* input);
214  char* last_debugger_input() { return last_debugger_input_; }
215 
216  // ICache checking.
217  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
218  size_t size);
219 
220  // Returns true if pc register contains one of the 'special_values' defined
221  // below (bad_lr, end_sim_pc).
222  bool has_bad_pc() const;
223 
224  // EABI variant for double arguments in use.
225  bool use_eabi_hardfloat() {
226 #if USE_EABI_HARDFLOAT
227  return true;
228 #else
229  return false;
230 #endif
231  }
232 
233  private:
234  enum special_values {
235  // Known bad pc value to ensure that the simulator does not execute
236  // without being properly setup.
237  bad_lr = -1,
238  // A pc value used to signal the simulator to stop execution. Generally
239  // the lr is set to this value on transition from native C code to
240  // simulated execution, so that the simulator can "return" to the native
241  // C code.
242  end_sim_pc = -2
243  };
244 
245  // Unsupported instructions use Format to print an error and stop execution.
246  void Format(Instruction* instr, const char* format);
247 
248  // Checks if the current instruction should be executed based on its
249  // condition bits.
250  inline bool ConditionallyExecute(Instruction* instr);
251 
252  // Helper functions to set the conditional flags in the architecture state.
253  void SetNZFlags(int32_t val);
254  void SetCFlag(bool val);
255  void SetVFlag(bool val);
256  bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
257  bool BorrowFrom(int32_t left, int32_t right);
258  bool OverflowFrom(int32_t alu_out,
259  int32_t left,
260  int32_t right,
261  bool addition);
262 
263  inline int GetCarry() {
264  return c_flag_ ? 1 : 0;
265  }
266 
267  // Support for VFP.
268  void Compute_FPSCR_Flags(double val1, double val2);
269  void Copy_FPSCR_to_APSR();
270  inline double canonicalizeNaN(double value);
271 
272  // Helper functions to decode common "addressing" modes
273  int32_t GetShiftRm(Instruction* instr, bool* carry_out);
274  int32_t GetImm(Instruction* instr, bool* carry_out);
275  int32_t ProcessPU(Instruction* instr,
276  int num_regs,
277  int operand_size,
278  intptr_t* start_address,
279  intptr_t* end_address);
280  void HandleRList(Instruction* instr, bool load);
281  void HandleVList(Instruction* inst);
282  void SoftwareInterrupt(Instruction* instr);
283 
284  // Stop helper functions.
285  inline bool isStopInstruction(Instruction* instr);
286  inline bool isWatchedStop(uint32_t bkpt_code);
287  inline bool isEnabledStop(uint32_t bkpt_code);
288  inline void EnableStop(uint32_t bkpt_code);
289  inline void DisableStop(uint32_t bkpt_code);
290  inline void IncreaseStopCounter(uint32_t bkpt_code);
291  void PrintStopInfo(uint32_t code);
292 
293  // Read and write memory.
294  inline uint8_t ReadBU(int32_t addr);
295  inline int8_t ReadB(int32_t addr);
296  inline void WriteB(int32_t addr, uint8_t value);
297  inline void WriteB(int32_t addr, int8_t value);
298 
299  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
300  inline int16_t ReadH(int32_t addr, Instruction* instr);
301  // Note: Overloaded on the sign of the value.
302  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
303  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
304 
305  inline int ReadW(int32_t addr, Instruction* instr);
306  inline void WriteW(int32_t addr, int value, Instruction* instr);
307 
308  int32_t* ReadDW(int32_t addr);
309  void WriteDW(int32_t addr, int32_t value1, int32_t value2);
310 
311  // Executing is handled based on the instruction type.
312  // Both type 0 and type 1 rolled into one.
313  void DecodeType01(Instruction* instr);
314  void DecodeType2(Instruction* instr);
315  void DecodeType3(Instruction* instr);
316  void DecodeType4(Instruction* instr);
317  void DecodeType5(Instruction* instr);
318  void DecodeType6(Instruction* instr);
319  void DecodeType7(Instruction* instr);
320 
321  // Support for VFP.
322  void DecodeTypeVFP(Instruction* instr);
323  void DecodeType6CoprocessorIns(Instruction* instr);
324  void DecodeSpecialCondition(Instruction* instr);
325 
326  void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr);
327  void DecodeVCMP(Instruction* instr);
328  void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr);
329  void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr);
330 
331  // Executes one instruction.
332  void InstructionDecode(Instruction* instr);
333 
334  // ICache.
335  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
336  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
337  int size);
338  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
339 
340  // Runtime call support.
341  static void* RedirectExternalReference(
342  void* external_function,
344 
345  // Handle arguments and return value for runtime FP functions.
346  void GetFpArgs(double* x, double* y, int32_t* z);
347  void SetFpResult(const double& result);
348  void TrashCallerSaveRegisters();
349 
350  template<class ReturnType, int register_size>
351  ReturnType GetFromVFPRegister(int reg_index);
352 
353  template<class InputType, int register_size>
354  void SetVFPRegister(int reg_index, const InputType& value);
355 
356  void CallInternal(byte* entry);
357 
358  // Architecture state.
359  // Saturating instructions require a Q flag to indicate saturation.
360  // There is currently no way to read the CPSR directly, and thus read the Q
361  // flag, so this is left unimplemented.
362  int32_t registers_[16];
363  bool n_flag_;
364  bool z_flag_;
365  bool c_flag_;
366  bool v_flag_;
367 
368  // VFP architecture state.
369  unsigned int vfp_registers_[num_d_registers * 2];
370  bool n_flag_FPSCR_;
371  bool z_flag_FPSCR_;
372  bool c_flag_FPSCR_;
373  bool v_flag_FPSCR_;
374 
375  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
376  VFPRoundingMode FPSCR_rounding_mode_;
377  bool FPSCR_default_NaN_mode_;
378 
379  // VFP FP exception flags architecture state.
380  bool inv_op_vfp_flag_;
381  bool div_zero_vfp_flag_;
382  bool overflow_vfp_flag_;
383  bool underflow_vfp_flag_;
384  bool inexact_vfp_flag_;
385 
386  // Simulator support.
387  char* stack_;
388  bool pc_modified_;
389  int icount_;
390 
391  // Debugger input.
392  char* last_debugger_input_;
393 
394  // Icache simulation
395  v8::internal::HashMap* i_cache_;
396 
397  // Registered breakpoints.
398  Instruction* break_pc_;
399  Instr break_instr_;
400 
401  v8::internal::Isolate* isolate_;
402 
403  // A stop is watched if its code is less than kNumOfWatchedStops.
404  // Only watched stops support enabling/disabling and the counter feature.
405  static const uint32_t kNumOfWatchedStops = 256;
406 
407  // Breakpoint is disabled if bit 31 is set.
408  static const uint32_t kStopDisabledBit = 1 << 31;
409 
410  // A stop is enabled, meaning the simulator will stop when meeting the
411  // instruction, if bit 31 of watched_stops_[code].count is unset.
412  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
413  // the breakpoint was hit or gone through.
414  struct StopCountAndDesc {
415  uint32_t count;
416  char* desc;
417  };
418  StopCountAndDesc watched_stops_[kNumOfWatchedStops];
419 };
420 
421 
422 // When running with the simulator transition into simulated execution at this
423 // point.
424 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
425  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
426  FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
427 
428 #define CALL_GENERATED_FP_INT(entry, p0, p1) \
429  Simulator::current(Isolate::Current())->CallFPReturnsInt( \
430  FUNCTION_ADDR(entry), p0, p1)
431 
432 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
433  Simulator::current(Isolate::Current())->Call( \
434  entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
435 
436 
437 // The simulator has its own stack. Thus it has a different stack limit from
438 // the C-based native code. Setting the c_limit to indicate a very small
439 // stack cause stack overflow errors, since the simulator ignores the input.
440 // This is unlikely to be an issue in practice, though it might cause testing
441 // trouble down the line.
442 class SimulatorStack : public v8::internal::AllStatic {
443  public:
444  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
445  uintptr_t c_limit) {
446  return Simulator::current(isolate)->StackLimit();
447  }
448 
449  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
450  Simulator* sim = Simulator::current(Isolate::Current());
451  return sim->PushAddress(try_catch_address);
452  }
453 
454  static inline void UnregisterCTryCatch() {
455  Simulator::current(Isolate::Current())->PopAddress();
456  }
457 };
458 
459 } } // namespace v8::internal
460 
461 #endif // !defined(USE_SIMULATOR)
462 #endif // V8_ARM_SIMULATOR_ARM_H_
static void UnregisterCTryCatch()
Definition: simulator-arm.h:55
static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address)
Definition: simulator-arm.h:51
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 USE(T)
Definition: macros.h:322
unsigned short uint16_t
Definition: unicode.cc:23
signed short int16_t
Definition: unicode.cc:22
int int32_t
Definition: unicode.cc:24
const DwVfpRegister d27
const LowDwVfpRegister d2
const SwVfpRegister s18
const Register r2
const QwNeonRegister q13
const LowDwVfpRegister d7
const SwVfpRegister s27
const LowDwVfpRegister d6
const QwNeonRegister q8
const SwVfpRegister s13
TypeImpl< ZoneTypeConfig > Type
const SwVfpRegister s29
const LowDwVfpRegister d9
const Register r10
const SwVfpRegister s17
const LowDwVfpRegister d1
const Register r6
const SwVfpRegister s11
const SwVfpRegister s1
const LowDwVfpRegister d5
const Register r0
const QwNeonRegister q5
const SwVfpRegister s25
const LowDwVfpRegister d0
const SwVfpRegister s24
const SwVfpRegister s2
const SwVfpRegister s0
const Register r3
const QwNeonRegister q10
const DwVfpRegister d31
const DwVfpRegister d21
const QwNeonRegister q1
const DwVfpRegister d18
const DwVfpRegister d20
const LowDwVfpRegister d8
const LowDwVfpRegister d12
const QwNeonRegister q3
const Register sp
const Register r11
const QwNeonRegister q6
const SwVfpRegister s19
const SwVfpRegister s20
const SwVfpRegister s22
const Register r4
const Register r12
const SwVfpRegister s28
const SwVfpRegister s23
const QwNeonRegister q15
const SwVfpRegister s26
const Register r9
const SwVfpRegister s15
const QwNeonRegister q7
const SwVfpRegister s3
const Register pc
const DwVfpRegister d29
const SwVfpRegister s9
const SwVfpRegister s16
const SwVfpRegister s30
const Register r5
const LowDwVfpRegister d11
const Register lr
const SwVfpRegister s6
byte * Address
Definition: globals.h:101
const Register r8
const Register r1
const SwVfpRegister s7
const DwVfpRegister d16
const DwVfpRegister d17
const Register no_reg
const QwNeonRegister q2
const Register r13
const DwVfpRegister d26
const QwNeonRegister q0
const SwVfpRegister s31
const QwNeonRegister q4
const DwVfpRegister d23
const QwNeonRegister q11
const SwVfpRegister s14
const Register r15
const SwVfpRegister s10
const DwVfpRegister d30
const DwVfpRegister d28
const LowDwVfpRegister d13
const SwVfpRegister s4
const LowDwVfpRegister d3
int(* arm_regexp_matcher)(String *, int, const byte *, const byte *, void *, int *, int, Address, int, Isolate *)
Definition: simulator-arm.h:28
const Register r14
const DwVfpRegister d22
const DwVfpRegister d25
const SwVfpRegister s21
const SwVfpRegister s12
const LowDwVfpRegister d10
const QwNeonRegister q14
const LowDwVfpRegister d15
const DwVfpRegister d24
const SwVfpRegister s8
const SwVfpRegister s5
const LowDwVfpRegister d14
const QwNeonRegister q12
const LowDwVfpRegister d4
const DwVfpRegister d19
const QwNeonRegister q9
const Register r7
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20