• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_EXECUTION_PPC_SIMULATOR_PPC_H_
13 #define V8_EXECUTION_PPC_SIMULATOR_PPC_H_
14 
15 // globals.h defines USE_SIMULATOR.
16 #include "src/common/globals.h"
17 
18 #if defined(USE_SIMULATOR)
19 // Running with a simulator.
20 
21 #include "src/base/hashmap.h"
22 #include "src/base/lazy-instance.h"
23 #include "src/base/platform/mutex.h"
24 #include "src/base/platform/wrappers.h"
25 #include "src/codegen/assembler.h"
26 #include "src/codegen/ppc/constants-ppc.h"
27 #include "src/execution/simulator-base.h"
28 #include "src/utils/allocation.h"
29 
30 namespace v8 {
31 namespace internal {
32 
33 class CachePage {
34  public:
35   static const int LINE_VALID = 0;
36   static const int LINE_INVALID = 1;
37 
38   static const int kPageShift = 12;
39   static const int kPageSize = 1 << kPageShift;
40   static const int kPageMask = kPageSize - 1;
41   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
42   static const int kLineLength = 1 << kLineShift;
43   static const int kLineMask = kLineLength - 1;
44 
CachePage()45   CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
46 
ValidityByte(int offset)47   char* ValidityByte(int offset) {
48     return &validity_map_[offset >> kLineShift];
49   }
50 
CachedData(int offset)51   char* CachedData(int offset) { return &data_[offset]; }
52 
53  private:
54   char data_[kPageSize];  // The cached data.
55   static const int kValidityMapSize = kPageSize >> kLineShift;
56   char validity_map_[kValidityMapSize];  // One byte per line.
57 };
58 
59 class Simulator : public SimulatorBase {
60  public:
61   friend class PPCDebugger;
62   enum Register {
63     no_reg = -1,
64     r0 = 0,
65     sp,
66     r2,
67     r3,
68     r4,
69     r5,
70     r6,
71     r7,
72     r8,
73     r9,
74     r10,
75     r11,
76     r12,
77     r13,
78     r14,
79     r15,
80     r16,
81     r17,
82     r18,
83     r19,
84     r20,
85     r21,
86     r22,
87     r23,
88     r24,
89     r25,
90     r26,
91     r27,
92     r28,
93     r29,
94     r30,
95     fp,
96     kNumGPRs = 32,
97     d0 = 0,
98     d1,
99     d2,
100     d3,
101     d4,
102     d5,
103     d6,
104     d7,
105     d8,
106     d9,
107     d10,
108     d11,
109     d12,
110     d13,
111     d14,
112     d15,
113     d16,
114     d17,
115     d18,
116     d19,
117     d20,
118     d21,
119     d22,
120     d23,
121     d24,
122     d25,
123     d26,
124     d27,
125     d28,
126     d29,
127     d30,
128     d31,
129     kNumFPRs = 32,
130     // PPC Simd registers are a serapre set from Floating Point registers. Refer
131     // to register-ppc.h for more details.
132     v0 = 0,
133     v1,
134     v2,
135     v3,
136     v4,
137     v5,
138     v6,
139     v7,
140     v8,
141     v9,
142     v10,
143     v11,
144     v12,
145     v13,
146     v14,
147     v15,
148     v16,
149     v17,
150     v18,
151     v19,
152     v20,
153     v21,
154     v22,
155     v23,
156     v24,
157     v25,
158     v26,
159     v27,
160     v28,
161     v29,
162     v30,
163     v31,
164     kNumSIMDRs = 32
165   };
166 
167   explicit Simulator(Isolate* isolate);
168   ~Simulator();
169 
170   // The currently executing Simulator instance. Potentially there can be one
171   // for each native thread.
172   static Simulator* current(v8::internal::Isolate* isolate);
173 
174   // Accessors for register state.
175   void set_register(int reg, intptr_t value);
176   intptr_t get_register(int reg) const;
177   double get_double_from_register_pair(int reg);
set_d_register_from_double(int dreg,const double dbl)178   void set_d_register_from_double(int dreg, const double dbl) {
179     DCHECK(dreg >= 0 && dreg < kNumFPRs);
180     *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
181   }
get_double_from_d_register(int dreg)182   double get_double_from_d_register(int dreg) {
183     DCHECK(dreg >= 0 && dreg < kNumFPRs);
184     return *bit_cast<double*>(&fp_registers_[dreg]);
185   }
set_d_register(int dreg,int64_t value)186   void set_d_register(int dreg, int64_t value) {
187     DCHECK(dreg >= 0 && dreg < kNumFPRs);
188     fp_registers_[dreg] = value;
189   }
get_d_register(int dreg)190   int64_t get_d_register(int dreg) {
191     DCHECK(dreg >= 0 && dreg < kNumFPRs);
192     return fp_registers_[dreg];
193   }
194 
195   // Special case of set_register and get_register to access the raw PC value.
196   void set_pc(intptr_t value);
197   intptr_t get_pc() const;
198 
get_sp()199   Address get_sp() const { return static_cast<Address>(get_register(sp)); }
200 
201   // Accessor to the internal Link Register
202   intptr_t get_lr() const;
203 
204   // Accessor to the internal simulator stack area.
205   uintptr_t StackLimit(uintptr_t c_limit) const;
206 
207   // Executes PPC instructions until the PC reaches end_sim_pc.
208   void Execute();
209 
210   template <typename Return, typename... Args>
Call(Address entry,Args...args)211   Return Call(Address entry, Args... args) {
212     return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
213   }
214 
215   // Alternative: call a 2-argument double function.
216   void CallFP(Address entry, double d0, double d1);
217   int32_t CallFPReturnsInt(Address entry, double d0, double d1);
218   double CallFPReturnsDouble(Address entry, double d0, double d1);
219 
220   // Push an address onto the JS stack.
221   uintptr_t PushAddress(uintptr_t address);
222 
223   // Pop an address from the JS stack.
224   uintptr_t PopAddress();
225 
226   // Debugger input.
227   void set_last_debugger_input(char* input);
last_debugger_input()228   char* last_debugger_input() { return last_debugger_input_; }
229 
230   // Redirection support.
231   static void SetRedirectInstruction(Instruction* instruction);
232 
233   // ICache checking.
234   static bool ICacheMatch(void* one, void* two);
235   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
236                           size_t size);
237 
238   // Returns true if pc register contains one of the 'special_values' defined
239   // below (bad_lr, end_sim_pc).
240   bool has_bad_pc() const;
241 
242   enum special_values {
243     // Known bad pc value to ensure that the simulator does not execute
244     // without being properly setup.
245     bad_lr = -1,
246     // A pc value used to signal the simulator to stop execution.  Generally
247     // the lr is set to this value on transition from native C code to
248     // simulated execution, so that the simulator can "return" to the native
249     // C code.
250     end_sim_pc = -2
251   };
252 
253   intptr_t CallImpl(Address entry, int argument_count,
254                     const intptr_t* arguments);
255 
256   enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG };
257 
258   // Unsupported instructions use Format to print an error and stop execution.
259   void Format(Instruction* instr, const char* format);
260 
261   // Helper functions to set the conditional flags in the architecture state.
262   bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
263   bool BorrowFrom(int32_t left, int32_t right);
264   bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
265                     bool addition);
266 
267   // Helper functions to decode common "addressing" modes
268   int32_t GetShiftRm(Instruction* instr, bool* carry_out);
269   int32_t GetImm(Instruction* instr, bool* carry_out);
270   void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
271                   intptr_t* start_address, intptr_t* end_address);
272   void HandleRList(Instruction* instr, bool load);
273   void HandleVList(Instruction* inst);
274   void SoftwareInterrupt(Instruction* instr);
275   void DebugAtNextPC();
276 
277   // Stop helper functions.
278   inline bool isStopInstruction(Instruction* instr);
279   inline bool isWatchedStop(uint32_t bkpt_code);
280   inline bool isEnabledStop(uint32_t bkpt_code);
281   inline void EnableStop(uint32_t bkpt_code);
282   inline void DisableStop(uint32_t bkpt_code);
283   inline void IncreaseStopCounter(uint32_t bkpt_code);
284   void PrintStopInfo(uint32_t code);
285 
286   // Read and write memory.
287   template <typename T>
Read(uintptr_t address,T * value)288   inline void Read(uintptr_t address, T* value) {
289     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
290     memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
291   }
292 
293   template <typename T>
ReadEx(uintptr_t address,T * value)294   inline void ReadEx(uintptr_t address, T* value) {
295     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
296     GlobalMonitor::Get()->NotifyLoadExcl(
297         address, static_cast<TransactionSize>(sizeof(T)),
298         isolate_->thread_id());
299     memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
300   }
301 
302   template <typename T>
Write(uintptr_t address,T value)303   inline void Write(uintptr_t address, T value) {
304     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
305     GlobalMonitor::Get()->NotifyStore(address,
306                                       static_cast<TransactionSize>(sizeof(T)),
307                                       isolate_->thread_id());
308     memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
309   }
310 
311   template <typename T>
WriteEx(uintptr_t address,T value)312   inline int32_t WriteEx(uintptr_t address, T value) {
313     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
314     if (GlobalMonitor::Get()->NotifyStoreExcl(
315             address, static_cast<TransactionSize>(sizeof(T)),
316             isolate_->thread_id())) {
317       memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
318       return 0;
319     } else {
320       return 1;
321     }
322   }
323 
324   // Byte Reverse.
__builtin_bswap128(__uint128_t v)325   static inline __uint128_t __builtin_bswap128(__uint128_t v) {
326     union {
327       uint64_t u64[2];
328       __uint128_t u128;
329     } res, val;
330     val.u128 = v;
331     res.u64[0] = __builtin_bswap64(val.u64[1]);
332     res.u64[1] = __builtin_bswap64(val.u64[0]);
333     return res.u128;
334   }
335 
336 #define RW_VAR_LIST(V)      \
337   V(QWU, unsigned __int128) \
338   V(QW, __int128)           \
339   V(DWU, uint64_t)          \
340   V(DW, int64_t)            \
341   V(WU, uint32_t)           \
342   V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t)
343 
344 #define GENERATE_RW_FUNC(size, type)                   \
345   inline type Read##size(uintptr_t addr);              \
346   inline type ReadEx##size(uintptr_t addr);            \
347   inline void Write##size(uintptr_t addr, type value); \
348   inline int32_t WriteEx##size(uintptr_t addr, type value);
349 
350   RW_VAR_LIST(GENERATE_RW_FUNC)
351 #undef GENERATE_RW_FUNC
352 
353   void Trace(Instruction* instr);
354   void SetCR0(intptr_t result, bool setSO = false);
355   void SetCR6(bool true_for_all, bool false_for_all);
356   void ExecuteBranchConditional(Instruction* instr, BCType type);
357   void ExecuteGeneric(Instruction* instr);
358 
SetFPSCR(int bit)359   void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
ClearFPSCR(int bit)360   void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); }
361 
362   // Executes one instruction.
363   void ExecuteInstruction(Instruction* instr);
364 
365   // ICache.
366   static void CheckICache(base::CustomMatcherHashMap* i_cache,
367                           Instruction* instr);
368   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
369                            int size);
370   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
371                                  void* page);
372 
373   // Handle arguments and return value for runtime FP functions.
374   void GetFpArgs(double* x, double* y, intptr_t* z);
375   void SetFpResult(const double& result);
376   void TrashCallerSaveRegisters();
377 
378   void CallInternal(Address entry);
379 
380   // Architecture state.
381   // Saturating instructions require a Q flag to indicate saturation.
382   // There is currently no way to read the CPSR directly, and thus read the Q
383   // flag, so this is left unimplemented.
384   intptr_t registers_[kNumGPRs];
385   int32_t condition_reg_;
386   int32_t fp_condition_reg_;
387   intptr_t special_reg_lr_;
388   intptr_t special_reg_pc_;
389   intptr_t special_reg_ctr_;
390   int32_t special_reg_xer_;
391 
392   int64_t fp_registers_[kNumFPRs];
393 
394   // Simd registers.
395   union simdr_t {
396     int8_t int8[16];
397     uint8_t uint8[16];
398     int16_t int16[8];
399     uint16_t uint16[8];
400     int32_t int32[4];
401     uint32_t uint32[4];
402     int64_t int64[2];
403     uint64_t uint64[2];
404     float f32[4];
405     double f64[2];
406   };
407   simdr_t simd_registers_[kNumSIMDRs];
408 
409   // Vector register lane numbers on IBM machines are reversed compared to
410   // x64. For example, doing an I32x4 extract_lane with lane number 0 on x64
411   // will be equal to lane number 3 on IBM machines. Vector registers are only
412   // used for compiling Wasm code at the moment. To keep the Wasm
413   // simulation accurate, we need to make sure accessing a lane is correctly
414   // simulated and as such we reverse the lane number on the getters and setters
415   // below. We need to be careful when getting/setting values on the Low or High
416   // side of a simulated register. In the simulation, "Low" is equal to the MSB
417   // and "High" is equal to the LSB in memory. "force_ibm_lane_numbering" could
418   // be used to disabled automatic lane number reversal and help with accessing
419   // the Low or High side of a simulated register.
420   template <class T>
421   T get_simd_register_by_lane(int reg, int lane,
422                               bool force_ibm_lane_numbering = true) {
423     if (force_ibm_lane_numbering) {
424       lane = (kSimd128Size / sizeof(T)) - 1 - lane;
425     }
426     CHECK_LE(lane, kSimd128Size / sizeof(T));
427     CHECK_LT(reg, kNumSIMDRs);
428     CHECK_GE(lane, 0);
429     CHECK_GE(reg, 0);
430     return (reinterpret_cast<T*>(&simd_registers_[reg]))[lane];
431   }
432 
433   template <class T>
get_simd_register_bytes(int reg,int byte_from)434   T get_simd_register_bytes(int reg, int byte_from) {
435     // Byte location is reversed in memory.
436     int from = kSimd128Size - 1 - (byte_from + sizeof(T) - 1);
437     void* src = bit_cast<uint8_t*>(&simd_registers_[reg]) + from;
438     T dst;
439     memcpy(&dst, src, sizeof(T));
440     return dst;
441   }
442 
443   template <class T>
444   void set_simd_register_by_lane(int reg, int lane, const T& value,
445                                  bool force_ibm_lane_numbering = true) {
446     if (force_ibm_lane_numbering) {
447       lane = (kSimd128Size / sizeof(T)) - 1 - lane;
448     }
449     CHECK_LE(lane, kSimd128Size / sizeof(T));
450     CHECK_LT(reg, kNumSIMDRs);
451     CHECK_GE(lane, 0);
452     CHECK_GE(reg, 0);
453     (reinterpret_cast<T*>(&simd_registers_[reg]))[lane] = value;
454   }
455 
456   template <class T>
set_simd_register_bytes(int reg,int byte_from,T value)457   void set_simd_register_bytes(int reg, int byte_from, T value) {
458     // Byte location is reversed in memory.
459     int from = kSimd128Size - 1 - (byte_from + sizeof(T) - 1);
460     void* dst = bit_cast<uint8_t*>(&simd_registers_[reg]) + from;
461     memcpy(dst, &value, sizeof(T));
462   }
463 
get_simd_register(int reg)464   simdr_t& get_simd_register(int reg) { return simd_registers_[reg]; }
465 
set_simd_register(int reg,const simdr_t & value)466   void set_simd_register(int reg, const simdr_t& value) {
467     simd_registers_[reg] = value;
468   }
469 
470   // Simulator support.
471   char* stack_;
472   static const size_t stack_protection_size_ = 256 * kSystemPointerSize;
473   bool pc_modified_;
474   int icount_;
475 
476   // Debugger input.
477   char* last_debugger_input_;
478 
479   // Registered breakpoints.
480   Instruction* break_pc_;
481   Instr break_instr_;
482 
483   v8::internal::Isolate* isolate_;
484 
485   // A stop is watched if its code is less than kNumOfWatchedStops.
486   // Only watched stops support enabling/disabling and the counter feature.
487   static const uint32_t kNumOfWatchedStops = 256;
488 
489   // Breakpoint is disabled if bit 31 is set.
490   static const uint32_t kStopDisabledBit = 1 << 31;
491 
492   // A stop is enabled, meaning the simulator will stop when meeting the
493   // instruction, if bit 31 of watched_stops_[code].count is unset.
494   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
495   // the breakpoint was hit or gone through.
496   struct StopCountAndDesc {
497     uint32_t count;
498     char* desc;
499   };
500   StopCountAndDesc watched_stops_[kNumOfWatchedStops];
501 
502   // Synchronization primitives. See ARM DDI 0406C.b, A2.9.
503   enum class MonitorAccess {
504     Open,
505     Exclusive,
506   };
507 
508   enum class TransactionSize {
509     None = 0,
510     Byte = 1,
511     HalfWord = 2,
512     Word = 4,
513     DWord = 8,
514   };
515 
516   class GlobalMonitor {
517    public:
518     // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
519     base::Mutex mutex;
520 
521     void NotifyLoadExcl(uintptr_t addr, TransactionSize size,
522                         ThreadId thread_id);
523     void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id);
524     bool NotifyStoreExcl(uintptr_t addr, TransactionSize size,
525                          ThreadId thread_id);
526 
527     static GlobalMonitor* Get();
528 
529    private:
530     // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
531     GlobalMonitor() = default;
532     friend class base::LeakyObject<GlobalMonitor>;
533 
534     void Clear();
535 
536     MonitorAccess access_state_ = MonitorAccess::Open;
537     uintptr_t tagged_addr_ = 0;
538     TransactionSize size_ = TransactionSize::None;
539     ThreadId thread_id_ = ThreadId::Invalid();
540   };
541 };
542 
543 }  // namespace internal
544 }  // namespace v8
545 
546 #endif  // defined(USE_SIMULATOR)
547 #endif  // V8_EXECUTION_PPC_SIMULATOR_PPC_H_
548