Home | History | Annotate | Download | only in ppc
      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 
      6 // Declares a Simulator for PPC instructions if we are not generating a native
      7 // PPC binary. This Simulator allows us to run and debug PPC 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 PPC HW platform.
     12 
     13 #ifndef V8_PPC_SIMULATOR_PPC_H_
     14 #define V8_PPC_SIMULATOR_PPC_H_
     15 
     16 #include "src/allocation.h"
     17 
     18 #if !defined(USE_SIMULATOR)
     19 // Running without a simulator on a native ppc 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(isolate, entry, p0, p1, p2, p3, p4) \
     26   (entry(p0, p1, p2, p3, p4))
     27 
     28 typedef int (*ppc_regexp_matcher)(String*, int, const byte*, const byte*, int*,
     29                                   int, Address, int, void*, 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 ppc_regexp_matcher.
     34 // The ninth 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(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
     37                                    p7, p8)                                     \
     38   (FUNCTION_CAST<ppc_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7,    \
     39                                             NULL, p8))
     40 
     41 // The stack limit beyond which we will throw stack overflow errors in
     42 // generated code. Because generated code on ppc 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(v8::internal::Isolate* isolate,
     47                                             uintptr_t c_limit) {
     48     USE(isolate);
     49     return c_limit;
     50   }
     51 
     52   static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
     53                                             uintptr_t try_catch_address) {
     54     USE(isolate);
     55     return try_catch_address;
     56   }
     57 
     58   static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
     59     USE(isolate);
     60   }
     61 };
     62 }  // namespace internal
     63 }  // namespace v8
     64 
     65 #else  // !defined(USE_SIMULATOR)
     66 // Running with a simulator.
     67 
     68 #include "src/assembler.h"
     69 #include "src/hashmap.h"
     70 #include "src/ppc/constants-ppc.h"
     71 
     72 namespace v8 {
     73 namespace internal {
     74 
     75 class CachePage {
     76  public:
     77   static const int LINE_VALID = 0;
     78   static const int LINE_INVALID = 1;
     79 
     80   static const int kPageShift = 12;
     81   static const int kPageSize = 1 << kPageShift;
     82   static const int kPageMask = kPageSize - 1;
     83   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
     84   static const int kLineLength = 1 << kLineShift;
     85   static const int kLineMask = kLineLength - 1;
     86 
     87   CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
     88 
     89   char* ValidityByte(int offset) {
     90     return &validity_map_[offset >> kLineShift];
     91   }
     92 
     93   char* CachedData(int offset) { return &data_[offset]; }
     94 
     95  private:
     96   char data_[kPageSize];  // The cached data.
     97   static const int kValidityMapSize = kPageSize >> kLineShift;
     98   char validity_map_[kValidityMapSize];  // One byte per line.
     99 };
    100 
    101 
    102 class Simulator {
    103  public:
    104   friend class PPCDebugger;
    105   enum Register {
    106     no_reg = -1,
    107     r0 = 0,
    108     sp,
    109     r2,
    110     r3,
    111     r4,
    112     r5,
    113     r6,
    114     r7,
    115     r8,
    116     r9,
    117     r10,
    118     r11,
    119     r12,
    120     r13,
    121     r14,
    122     r15,
    123     r16,
    124     r17,
    125     r18,
    126     r19,
    127     r20,
    128     r21,
    129     r22,
    130     r23,
    131     r24,
    132     r25,
    133     r26,
    134     r27,
    135     r28,
    136     r29,
    137     r30,
    138     fp,
    139     kNumGPRs = 32,
    140     d0 = 0,
    141     d1,
    142     d2,
    143     d3,
    144     d4,
    145     d5,
    146     d6,
    147     d7,
    148     d8,
    149     d9,
    150     d10,
    151     d11,
    152     d12,
    153     d13,
    154     d14,
    155     d15,
    156     d16,
    157     d17,
    158     d18,
    159     d19,
    160     d20,
    161     d21,
    162     d22,
    163     d23,
    164     d24,
    165     d25,
    166     d26,
    167     d27,
    168     d28,
    169     d29,
    170     d30,
    171     d31,
    172     kNumFPRs = 32
    173   };
    174 
    175   explicit Simulator(Isolate* isolate);
    176   ~Simulator();
    177 
    178   // The currently executing Simulator instance. Potentially there can be one
    179   // for each native thread.
    180   static Simulator* current(v8::internal::Isolate* isolate);
    181 
    182   // Accessors for register state.
    183   void set_register(int reg, intptr_t value);
    184   intptr_t get_register(int reg) const;
    185   double get_double_from_register_pair(int reg);
    186   void set_d_register_from_double(int dreg, const double dbl) {
    187     DCHECK(dreg >= 0 && dreg < kNumFPRs);
    188     *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
    189   }
    190   double get_double_from_d_register(int dreg) {
    191     DCHECK(dreg >= 0 && dreg < kNumFPRs);
    192     return *bit_cast<double*>(&fp_registers_[dreg]);
    193   }
    194   void set_d_register(int dreg, int64_t value) {
    195     DCHECK(dreg >= 0 && dreg < kNumFPRs);
    196     fp_registers_[dreg] = value;
    197   }
    198   int64_t get_d_register(int dreg) {
    199     DCHECK(dreg >= 0 && dreg < kNumFPRs);
    200     return fp_registers_[dreg];
    201   }
    202 
    203   // Special case of set_register and get_register to access the raw PC value.
    204   void set_pc(intptr_t value);
    205   intptr_t get_pc() const;
    206 
    207   Address get_sp() const {
    208     return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
    209   }
    210 
    211   // Accessor to the internal simulator stack area.
    212   uintptr_t StackLimit(uintptr_t c_limit) const;
    213 
    214   // Executes PPC instructions until the PC reaches end_sim_pc.
    215   void Execute();
    216 
    217   // Call on program start.
    218   static void Initialize(Isolate* isolate);
    219 
    220   static void TearDown(HashMap* i_cache, Redirection* first);
    221 
    222   // V8 generally calls into generated JS code with 5 parameters and into
    223   // generated RegExp code with 7 parameters. This is a convenience function,
    224   // which sets up the simulator state and grabs the result on return.
    225   intptr_t Call(byte* entry, int argument_count, ...);
    226   // Alternative: call a 2-argument double function.
    227   void CallFP(byte* entry, double d0, double d1);
    228   int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
    229   double CallFPReturnsDouble(byte* entry, double d0, double d1);
    230 
    231   // Push an address onto the JS stack.
    232   uintptr_t PushAddress(uintptr_t address);
    233 
    234   // Pop an address from the JS stack.
    235   uintptr_t PopAddress();
    236 
    237   // Debugger input.
    238   void set_last_debugger_input(char* input);
    239   char* last_debugger_input() { return last_debugger_input_; }
    240 
    241   // ICache checking.
    242   static void FlushICache(v8::internal::HashMap* i_cache, void* start,
    243                           size_t size);
    244 
    245   // Returns true if pc register contains one of the 'special_values' defined
    246   // below (bad_lr, end_sim_pc).
    247   bool has_bad_pc() const;
    248 
    249  private:
    250   enum special_values {
    251     // Known bad pc value to ensure that the simulator does not execute
    252     // without being properly setup.
    253     bad_lr = -1,
    254     // A pc value used to signal the simulator to stop execution.  Generally
    255     // the lr is set to this value on transition from native C code to
    256     // simulated execution, so that the simulator can "return" to the native
    257     // C code.
    258     end_sim_pc = -2
    259   };
    260 
    261   enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG };
    262 
    263   // Unsupported instructions use Format to print an error and stop execution.
    264   void Format(Instruction* instr, const char* format);
    265 
    266   // Helper functions to set the conditional flags in the architecture state.
    267   bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
    268   bool BorrowFrom(int32_t left, int32_t right);
    269   bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
    270                     bool addition);
    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   void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
    276                   intptr_t* start_address, intptr_t* end_address);
    277   void HandleRList(Instruction* instr, bool load);
    278   void HandleVList(Instruction* inst);
    279   void SoftwareInterrupt(Instruction* instr);
    280 
    281   // Stop helper functions.
    282   inline bool isStopInstruction(Instruction* instr);
    283   inline bool isWatchedStop(uint32_t bkpt_code);
    284   inline bool isEnabledStop(uint32_t bkpt_code);
    285   inline void EnableStop(uint32_t bkpt_code);
    286   inline void DisableStop(uint32_t bkpt_code);
    287   inline void IncreaseStopCounter(uint32_t bkpt_code);
    288   void PrintStopInfo(uint32_t code);
    289 
    290   // Read and write memory.
    291   inline uint8_t ReadBU(intptr_t addr);
    292   inline int8_t ReadB(intptr_t addr);
    293   inline void WriteB(intptr_t addr, uint8_t value);
    294   inline void WriteB(intptr_t addr, int8_t value);
    295 
    296   inline uint16_t ReadHU(intptr_t addr, Instruction* instr);
    297   inline int16_t ReadH(intptr_t addr, Instruction* instr);
    298   // Note: Overloaded on the sign of the value.
    299   inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr);
    300   inline void WriteH(intptr_t addr, int16_t value, Instruction* instr);
    301 
    302   inline uint32_t ReadWU(intptr_t addr, Instruction* instr);
    303   inline int32_t ReadW(intptr_t addr, Instruction* instr);
    304   inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr);
    305   inline void WriteW(intptr_t addr, int32_t value, Instruction* instr);
    306 
    307   intptr_t* ReadDW(intptr_t addr);
    308   void WriteDW(intptr_t addr, int64_t value);
    309 
    310   void Trace(Instruction* instr);
    311   void SetCR0(intptr_t result, bool setSO = false);
    312   void ExecuteBranchConditional(Instruction* instr, BCType type);
    313   void ExecuteExt1(Instruction* instr);
    314   bool ExecuteExt2_10bit(Instruction* instr);
    315   bool ExecuteExt2_9bit_part1(Instruction* instr);
    316   bool ExecuteExt2_9bit_part2(Instruction* instr);
    317   void ExecuteExt2_5bit(Instruction* instr);
    318   void ExecuteExt2(Instruction* instr);
    319   void ExecuteExt3(Instruction* instr);
    320   void ExecuteExt4(Instruction* instr);
    321 #if V8_TARGET_ARCH_PPC64
    322   void ExecuteExt5(Instruction* instr);
    323 #endif
    324   void ExecuteGeneric(Instruction* instr);
    325 
    326   void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
    327   void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); }
    328 
    329   // Executes one instruction.
    330   void ExecuteInstruction(Instruction* instr);
    331 
    332   // ICache.
    333   static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
    334   static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
    335                            int size);
    336   static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
    337 
    338   // Runtime call support.
    339   static void* RedirectExternalReference(
    340       Isolate* isolate, void* external_function,
    341       v8::internal::ExternalReference::Type type);
    342 
    343   // Handle arguments and return value for runtime FP functions.
    344   void GetFpArgs(double* x, double* y, intptr_t* z);
    345   void SetFpResult(const double& result);
    346   void TrashCallerSaveRegisters();
    347 
    348   void CallInternal(byte* entry);
    349 
    350   // Architecture state.
    351   // Saturating instructions require a Q flag to indicate saturation.
    352   // There is currently no way to read the CPSR directly, and thus read the Q
    353   // flag, so this is left unimplemented.
    354   intptr_t registers_[kNumGPRs];
    355   int32_t condition_reg_;
    356   int32_t fp_condition_reg_;
    357   intptr_t special_reg_lr_;
    358   intptr_t special_reg_pc_;
    359   intptr_t special_reg_ctr_;
    360   int32_t special_reg_xer_;
    361 
    362   int64_t fp_registers_[kNumFPRs];
    363 
    364   // Simulator support.
    365   char* stack_;
    366   static const size_t stack_protection_size_ = 256 * kPointerSize;
    367   bool pc_modified_;
    368   int icount_;
    369 
    370   // Debugger input.
    371   char* last_debugger_input_;
    372 
    373   // Icache simulation
    374   v8::internal::HashMap* i_cache_;
    375 
    376   // Registered breakpoints.
    377   Instruction* break_pc_;
    378   Instr break_instr_;
    379 
    380   v8::internal::Isolate* isolate_;
    381 
    382   // A stop is watched if its code is less than kNumOfWatchedStops.
    383   // Only watched stops support enabling/disabling and the counter feature.
    384   static const uint32_t kNumOfWatchedStops = 256;
    385 
    386   // Breakpoint is disabled if bit 31 is set.
    387   static const uint32_t kStopDisabledBit = 1 << 31;
    388 
    389   // A stop is enabled, meaning the simulator will stop when meeting the
    390   // instruction, if bit 31 of watched_stops_[code].count is unset.
    391   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
    392   // the breakpoint was hit or gone through.
    393   struct StopCountAndDesc {
    394     uint32_t count;
    395     char* desc;
    396   };
    397   StopCountAndDesc watched_stops_[kNumOfWatchedStops];
    398 };
    399 
    400 
    401 // When running with the simulator transition into simulated execution at this
    402 // point.
    403 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4)          \
    404   reinterpret_cast<Object*>(Simulator::current(isolate)->Call(           \
    405       FUNCTION_ADDR(entry), 5, (intptr_t)p0, (intptr_t)p1, (intptr_t)p2, \
    406       (intptr_t)p3, (intptr_t)p4))
    407 
    408 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
    409                                    p7, p8)                                     \
    410   Simulator::current(isolate)->Call(entry, 10, (intptr_t)p0, (intptr_t)p1,     \
    411                                     (intptr_t)p2, (intptr_t)p3, (intptr_t)p4,  \
    412                                     (intptr_t)p5, (intptr_t)p6, (intptr_t)p7,  \
    413                                     (intptr_t)NULL, (intptr_t)p8)
    414 
    415 
    416 // The simulator has its own stack. Thus it has a different stack limit from
    417 // the C-based native code.  The JS-based limit normally points near the end of
    418 // the simulator stack.  When the C-based limit is exhausted we reflect that by
    419 // lowering the JS-based limit as well, to make stack checks trigger.
    420 class SimulatorStack : public v8::internal::AllStatic {
    421  public:
    422   static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
    423                                             uintptr_t c_limit) {
    424     return Simulator::current(isolate)->StackLimit(c_limit);
    425   }
    426 
    427   static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
    428                                             uintptr_t try_catch_address) {
    429     Simulator* sim = Simulator::current(isolate);
    430     return sim->PushAddress(try_catch_address);
    431   }
    432 
    433   static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
    434     Simulator::current(isolate)->PopAddress();
    435   }
    436 };
    437 }  // namespace internal
    438 }  // namespace v8
    439 
    440 #endif  // !defined(USE_SIMULATOR)
    441 #endif  // V8_PPC_SIMULATOR_PPC_H_
    442