V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
simulator-ppc.h
1 // Copyright 2014 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 // Declares a Simulator for PPC instructions if we are not generating a native
6 // PPC binary. This Simulator allows us to run and debug PPC code generation on
7 // regular desktop machines.
8 // V8 calls into generated code via the GeneratedCode wrapper,
9 // which will start execution in the Simulator or forwards to the real entry
10 // on a PPC HW platform.
11 
12 #ifndef V8_PPC_SIMULATOR_PPC_H_
13 #define V8_PPC_SIMULATOR_PPC_H_
14 
15 #include "src/allocation.h"
16 #include "src/base/lazy-instance.h"
17 #include "src/base/platform/mutex.h"
18 
19 #if defined(USE_SIMULATOR)
20 // Running with a simulator.
21 
22 #include "src/assembler.h"
23 #include "src/base/hashmap.h"
24 #include "src/ppc/constants-ppc.h"
25 #include "src/simulator-base.h"
26 
27 namespace v8 {
28 namespace internal {
29 
30 class CachePage {
31  public:
32  static const int LINE_VALID = 0;
33  static const int LINE_INVALID = 1;
34 
35  static const int kPageShift = 12;
36  static const int kPageSize = 1 << kPageShift;
37  static const int kPageMask = kPageSize - 1;
38  static const int kLineShift = 2; // The cache line is only 4 bytes right now.
39  static const int kLineLength = 1 << kLineShift;
40  static const int kLineMask = kLineLength - 1;
41 
42  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
43 
44  char* ValidityByte(int offset) {
45  return &validity_map_[offset >> kLineShift];
46  }
47 
48  char* CachedData(int offset) { return &data_[offset]; }
49 
50  private:
51  char data_[kPageSize]; // The cached data.
52  static const int kValidityMapSize = kPageSize >> kLineShift;
53  char validity_map_[kValidityMapSize]; // One byte per line.
54 };
55 
56 class Simulator : public SimulatorBase {
57  public:
58  friend class PPCDebugger;
59  enum Register {
60  no_reg = -1,
61  r0 = 0,
62  sp,
63  r2,
64  r3,
65  r4,
66  r5,
67  r6,
68  r7,
69  r8,
70  r9,
71  r10,
72  r11,
73  r12,
74  r13,
75  r14,
76  r15,
77  r16,
78  r17,
79  r18,
80  r19,
81  r20,
82  r21,
83  r22,
84  r23,
85  r24,
86  r25,
87  r26,
88  r27,
89  r28,
90  r29,
91  r30,
92  fp,
93  kNumGPRs = 32,
94  d0 = 0,
95  d1,
96  d2,
97  d3,
98  d4,
99  d5,
100  d6,
101  d7,
102  d8,
103  d9,
104  d10,
105  d11,
106  d12,
107  d13,
108  d14,
109  d15,
110  d16,
111  d17,
112  d18,
113  d19,
114  d20,
115  d21,
116  d22,
117  d23,
118  d24,
119  d25,
120  d26,
121  d27,
122  d28,
123  d29,
124  d30,
125  d31,
126  kNumFPRs = 32
127  };
128 
129  explicit Simulator(Isolate* isolate);
130  ~Simulator();
131 
132  // The currently executing Simulator instance. Potentially there can be one
133  // for each native thread.
134  static Simulator* current(v8::internal::Isolate* isolate);
135 
136  // Accessors for register state.
137  void set_register(int reg, intptr_t value);
138  intptr_t get_register(int reg) const;
139  double get_double_from_register_pair(int reg);
140  void set_d_register_from_double(int dreg, const double dbl) {
141  DCHECK(dreg >= 0 && dreg < kNumFPRs);
142  *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
143  }
144  double get_double_from_d_register(int dreg) {
145  DCHECK(dreg >= 0 && dreg < kNumFPRs);
146  return *bit_cast<double*>(&fp_registers_[dreg]);
147  }
148  void set_d_register(int dreg, int64_t value) {
149  DCHECK(dreg >= 0 && dreg < kNumFPRs);
150  fp_registers_[dreg] = value;
151  }
152  int64_t get_d_register(int dreg) {
153  DCHECK(dreg >= 0 && dreg < kNumFPRs);
154  return fp_registers_[dreg];
155  }
156 
157  // Special case of set_register and get_register to access the raw PC value.
158  void set_pc(intptr_t value);
159  intptr_t get_pc() const;
160 
161  Address get_sp() const { return static_cast<Address>(get_register(sp)); }
162 
163  // Accessor to the internal simulator stack area.
164  uintptr_t StackLimit(uintptr_t c_limit) const;
165 
166  // Executes PPC instructions until the PC reaches end_sim_pc.
167  void Execute();
168 
169  template <typename Return, typename... Args>
170  Return Call(Address entry, Args... args) {
171  return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
172  }
173 
174  // Alternative: call a 2-argument double function.
175  void CallFP(Address entry, double d0, double d1);
176  int32_t CallFPReturnsInt(Address entry, double d0, double d1);
177  double CallFPReturnsDouble(Address entry, double d0, double d1);
178 
179  // Push an address onto the JS stack.
180  uintptr_t PushAddress(uintptr_t address);
181 
182  // Pop an address from the JS stack.
183  uintptr_t PopAddress();
184 
185  // Debugger input.
186  void set_last_debugger_input(char* input);
187  char* last_debugger_input() { return last_debugger_input_; }
188 
189  // Redirection support.
190  static void SetRedirectInstruction(Instruction* instruction);
191 
192  // ICache checking.
193  static bool ICacheMatch(void* one, void* two);
194  static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
195  size_t size);
196 
197  // Returns true if pc register contains one of the 'special_values' defined
198  // below (bad_lr, end_sim_pc).
199  bool has_bad_pc() const;
200 
201  private:
202  enum special_values {
203  // Known bad pc value to ensure that the simulator does not execute
204  // without being properly setup.
205  bad_lr = -1,
206  // A pc value used to signal the simulator to stop execution. Generally
207  // the lr is set to this value on transition from native C code to
208  // simulated execution, so that the simulator can "return" to the native
209  // C code.
210  end_sim_pc = -2
211  };
212 
213  intptr_t CallImpl(Address entry, int argument_count,
214  const intptr_t* arguments);
215 
216  enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG };
217 
218  // Unsupported instructions use Format to print an error and stop execution.
219  void Format(Instruction* instr, const char* format);
220 
221  // Helper functions to set the conditional flags in the architecture state.
222  bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
223  bool BorrowFrom(int32_t left, int32_t right);
224  bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
225  bool addition);
226 
227  // Helper functions to decode common "addressing" modes
228  int32_t GetShiftRm(Instruction* instr, bool* carry_out);
229  int32_t GetImm(Instruction* instr, bool* carry_out);
230  void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
231  intptr_t* start_address, intptr_t* end_address);
232  void HandleRList(Instruction* instr, bool load);
233  void HandleVList(Instruction* inst);
234  void SoftwareInterrupt(Instruction* instr);
235 
236  // Stop helper functions.
237  inline bool isStopInstruction(Instruction* instr);
238  inline bool isWatchedStop(uint32_t bkpt_code);
239  inline bool isEnabledStop(uint32_t bkpt_code);
240  inline void EnableStop(uint32_t bkpt_code);
241  inline void DisableStop(uint32_t bkpt_code);
242  inline void IncreaseStopCounter(uint32_t bkpt_code);
243  void PrintStopInfo(uint32_t code);
244 
245  // Read and write memory.
246  template <typename T>
247  inline void Read(uintptr_t address, T* value) {
248  base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
249  memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
250  }
251 
252  template <typename T>
253  inline void ReadEx(uintptr_t address, T* value) {
254  base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
255  global_monitor_.Pointer()->NotifyLoadExcl(
256  address, static_cast<TransactionSize>(sizeof(T)),
257  isolate_->thread_id());
258  memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
259  }
260 
261  template <typename T>
262  inline void Write(uintptr_t address, T value) {
263  base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
264  global_monitor_.Pointer()->NotifyStore(
265  address, static_cast<TransactionSize>(sizeof(T)),
266  isolate_->thread_id());
267  memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
268  }
269 
270  template <typename T>
271  inline int32_t WriteEx(uintptr_t address, T value) {
272  base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
273  if (global_monitor_.Pointer()->NotifyStoreExcl(
274  address, static_cast<TransactionSize>(sizeof(T)),
275  isolate_->thread_id())) {
276  memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
277  return 0;
278  } else {
279  return 1;
280  }
281  }
282 
283 #define RW_VAR_LIST(V) \
284  V(DWU, uint64_t) \
285  V(DW, int64_t) \
286  V(WU, uint32_t) \
287  V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t)
288 
289 #define GENERATE_RW_FUNC(size, type) \
290  inline type Read##size(uintptr_t addr); \
291  inline type ReadEx##size(uintptr_t addr); \
292  inline void Write##size(uintptr_t addr, type value); \
293  inline int32_t WriteEx##size(uintptr_t addr, type value);
294 
295  RW_VAR_LIST(GENERATE_RW_FUNC);
296 #undef GENERATE_RW_FUNC
297 
298  void Trace(Instruction* instr);
299  void SetCR0(intptr_t result, bool setSO = false);
300  void ExecuteBranchConditional(Instruction* instr, BCType type);
301  void ExecuteGeneric(Instruction* instr);
302 
303  void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
304  void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); }
305 
306  // Executes one instruction.
307  void ExecuteInstruction(Instruction* instr);
308 
309  // ICache.
310  static void CheckICache(base::CustomMatcherHashMap* i_cache,
311  Instruction* instr);
312  static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
313  int size);
314  static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
315  void* page);
316 
317  // Handle arguments and return value for runtime FP functions.
318  void GetFpArgs(double* x, double* y, intptr_t* z);
319  void SetFpResult(const double& result);
320  void TrashCallerSaveRegisters();
321 
322  void CallInternal(Address entry);
323 
324  // Architecture state.
325  // Saturating instructions require a Q flag to indicate saturation.
326  // There is currently no way to read the CPSR directly, and thus read the Q
327  // flag, so this is left unimplemented.
328  intptr_t registers_[kNumGPRs];
329  int32_t condition_reg_;
330  int32_t fp_condition_reg_;
331  intptr_t special_reg_lr_;
332  intptr_t special_reg_pc_;
333  intptr_t special_reg_ctr_;
334  int32_t special_reg_xer_;
335 
336  int64_t fp_registers_[kNumFPRs];
337 
338  // Simulator support.
339  char* stack_;
340  static const size_t stack_protection_size_ = 256 * kPointerSize;
341  bool pc_modified_;
342  int icount_;
343 
344  // Debugger input.
345  char* last_debugger_input_;
346 
347  // Registered breakpoints.
348  Instruction* break_pc_;
349  Instr break_instr_;
350 
351  v8::internal::Isolate* isolate_;
352 
353  // A stop is watched if its code is less than kNumOfWatchedStops.
354  // Only watched stops support enabling/disabling and the counter feature.
355  static const uint32_t kNumOfWatchedStops = 256;
356 
357  // Breakpoint is disabled if bit 31 is set.
358  static const uint32_t kStopDisabledBit = 1 << 31;
359 
360  // A stop is enabled, meaning the simulator will stop when meeting the
361  // instruction, if bit 31 of watched_stops_[code].count is unset.
362  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
363  // the breakpoint was hit or gone through.
364  struct StopCountAndDesc {
365  uint32_t count;
366  char* desc;
367  };
368  StopCountAndDesc watched_stops_[kNumOfWatchedStops];
369 
370  // Synchronization primitives. See ARM DDI 0406C.b, A2.9.
371  enum class MonitorAccess {
372  Open,
373  Exclusive,
374  };
375 
376  enum class TransactionSize {
377  None = 0,
378  Byte = 1,
379  HalfWord = 2,
380  Word = 4,
381  DWord = 8,
382  };
383 
384  class GlobalMonitor {
385  public:
386  GlobalMonitor();
387 
388  // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
389  base::Mutex mutex;
390 
391  void NotifyLoadExcl(uintptr_t addr, TransactionSize size,
392  ThreadId thread_id);
393  void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id);
394  bool NotifyStoreExcl(uintptr_t addr, TransactionSize size,
395  ThreadId thread_id);
396 
397  private:
398  void Clear();
399 
400  MonitorAccess access_state_;
401  uintptr_t tagged_addr_;
402  TransactionSize size_;
403  ThreadId thread_id_;
404  };
405 
406  static base::LazyInstance<GlobalMonitor>::type global_monitor_;
407 };
408 
409 } // namespace internal
410 } // namespace v8
411 
412 #endif // defined(USE_SIMULATOR)
413 #endif // V8_PPC_SIMULATOR_PPC_H_
Definition: libplatform.h:13
Definition: v8.h:3134