Home | History | Annotate | Download | only in arm
      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 ARM instructions if we are not generating a native
     30 // ARM binary. This Simulator allows us to run and debug ARM code generation on
     31 // 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 ARM HW platform.
     35 
     36 #ifndef V8_ARM_SIMULATOR_ARM_H_
     37 #define V8_ARM_SIMULATOR_ARM_H_
     38 
     39 #include "allocation.h"
     40 
     41 #if !defined(USE_SIMULATOR)
     42 // Running without a simulator on a native arm platform.
     43 
     44 namespace v8 {
     45 namespace internal {
     46 
     47 // When running without a simulator we call the entry directly.
     48 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
     49   (entry(p0, p1, p2, p3, p4))
     50 
     51 typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*,
     52                                   void*, int*, Address, int, Isolate*);
     53 
     54 
     55 // Call the generated regexp code directly. The code at the entry address
     56 // should act as a function matching the type arm_regexp_matcher.
     57 // The fifth argument is a dummy that reserves the space used for
     58 // the return address added by the ExitFrame in native calls.
     59 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
     60   (FUNCTION_CAST<arm_regexp_matcher>(entry)(                              \
     61       p0, p1, p2, p3, NULL, p4, p5, p6, p7))
     62 
     63 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
     64   reinterpret_cast<TryCatch*>(try_catch_address)
     65 
     66 // The stack limit beyond which we will throw stack overflow errors in
     67 // generated code. Because generated code on arm uses the C stack, we
     68 // just use the C stack limit.
     69 class SimulatorStack : public v8::internal::AllStatic {
     70  public:
     71   static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
     72     return c_limit;
     73   }
     74 
     75   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
     76     return try_catch_address;
     77   }
     78 
     79   static inline void UnregisterCTryCatch() { }
     80 };
     81 
     82 } }  // namespace v8::internal
     83 
     84 #else  // !defined(USE_SIMULATOR)
     85 // Running with a simulator.
     86 
     87 #include "constants-arm.h"
     88 #include "hashmap.h"
     89 #include "assembler.h"
     90 
     91 namespace v8 {
     92 namespace internal {
     93 
     94 class CachePage {
     95  public:
     96   static const int LINE_VALID = 0;
     97   static const int LINE_INVALID = 1;
     98 
     99   static const int kPageShift = 12;
    100   static const int kPageSize = 1 << kPageShift;
    101   static const int kPageMask = kPageSize - 1;
    102   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
    103   static const int kLineLength = 1 << kLineShift;
    104   static const int kLineMask = kLineLength - 1;
    105 
    106   CachePage() {
    107     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
    108   }
    109 
    110   char* ValidityByte(int offset) {
    111     return &validity_map_[offset >> kLineShift];
    112   }
    113 
    114   char* CachedData(int offset) {
    115     return &data_[offset];
    116   }
    117 
    118  private:
    119   char data_[kPageSize];   // The cached data.
    120   static const int kValidityMapSize = kPageSize >> kLineShift;
    121   char validity_map_[kValidityMapSize];  // One byte per line.
    122 };
    123 
    124 
    125 class Simulator {
    126  public:
    127   friend class ArmDebugger;
    128   enum Register {
    129     no_reg = -1,
    130     r0 = 0, r1, r2, r3, r4, r5, r6, r7,
    131     r8, r9, r10, r11, r12, r13, r14, r15,
    132     num_registers,
    133     sp = 13,
    134     lr = 14,
    135     pc = 15,
    136     s0 = 0, s1, s2, s3, s4, s5, s6, s7,
    137     s8, s9, s10, s11, s12, s13, s14, s15,
    138     s16, s17, s18, s19, s20, s21, s22, s23,
    139     s24, s25, s26, s27, s28, s29, s30, s31,
    140     num_s_registers = 32,
    141     d0 = 0, d1, d2, d3, d4, d5, d6, d7,
    142     d8, d9, d10, d11, d12, d13, d14, d15,
    143     num_d_registers = 16
    144   };
    145 
    146   Simulator();
    147   ~Simulator();
    148 
    149   // The currently executing Simulator instance. Potentially there can be one
    150   // for each native thread.
    151   static Simulator* current(v8::internal::Isolate* isolate);
    152 
    153   // Accessors for register state. Reading the pc value adheres to the ARM
    154   // architecture specification and is off by a 8 from the currently executing
    155   // instruction.
    156   void set_register(int reg, int32_t value);
    157   int32_t get_register(int reg) const;
    158   double get_double_from_register_pair(int reg);
    159   void set_dw_register(int dreg, const int* dbl);
    160 
    161   // Support for VFP.
    162   void set_s_register(int reg, unsigned int value);
    163   unsigned int get_s_register(int reg) const;
    164   void set_d_register_from_double(int dreg, const double& dbl);
    165   double get_double_from_d_register(int dreg);
    166   void set_s_register_from_float(int sreg, const float dbl);
    167   float get_float_from_s_register(int sreg);
    168   void set_s_register_from_sinteger(int reg, const int value);
    169   int get_sinteger_from_s_register(int reg);
    170 
    171   // Special case of set_register and get_register to access the raw PC value.
    172   void set_pc(int32_t value);
    173   int32_t get_pc() const;
    174 
    175   // Accessor to the internal simulator stack area.
    176   uintptr_t StackLimit() const;
    177 
    178   // Executes ARM instructions until the PC reaches end_sim_pc.
    179   void Execute();
    180 
    181   // Call on program start.
    182   static void Initialize();
    183 
    184   // V8 generally calls into generated JS code with 5 parameters and into
    185   // generated RegExp code with 7 parameters. This is a convenience function,
    186   // which sets up the simulator state and grabs the result on return.
    187   int32_t Call(byte* entry, int argument_count, ...);
    188 
    189   // Push an address onto the JS stack.
    190   uintptr_t PushAddress(uintptr_t address);
    191 
    192   // Pop an address from the JS stack.
    193   uintptr_t PopAddress();
    194 
    195   // ICache checking.
    196   static void FlushICache(v8::internal::HashMap* i_cache, void* start,
    197                           size_t size);
    198 
    199   // Returns true if pc register contains one of the 'special_values' defined
    200   // below (bad_lr, end_sim_pc).
    201   bool has_bad_pc() const;
    202 
    203  private:
    204   enum special_values {
    205     // Known bad pc value to ensure that the simulator does not execute
    206     // without being properly setup.
    207     bad_lr = -1,
    208     // A pc value used to signal the simulator to stop execution.  Generally
    209     // the lr is set to this value on transition from native C code to
    210     // simulated execution, so that the simulator can "return" to the native
    211     // C code.
    212     end_sim_pc = -2
    213   };
    214 
    215   // Unsupported instructions use Format to print an error and stop execution.
    216   void Format(Instruction* instr, const char* format);
    217 
    218   // Checks if the current instruction should be executed based on its
    219   // condition bits.
    220   bool ConditionallyExecute(Instruction* instr);
    221 
    222   // Helper functions to set the conditional flags in the architecture state.
    223   void SetNZFlags(int32_t val);
    224   void SetCFlag(bool val);
    225   void SetVFlag(bool val);
    226   bool CarryFrom(int32_t left, int32_t right);
    227   bool BorrowFrom(int32_t left, int32_t right);
    228   bool OverflowFrom(int32_t alu_out,
    229                     int32_t left,
    230                     int32_t right,
    231                     bool addition);
    232 
    233   // Support for VFP.
    234   void Compute_FPSCR_Flags(double val1, double val2);
    235   void Copy_FPSCR_to_APSR();
    236 
    237   // Helper functions to decode common "addressing" modes
    238   int32_t GetShiftRm(Instruction* instr, bool* carry_out);
    239   int32_t GetImm(Instruction* instr, bool* carry_out);
    240   void ProcessPUW(Instruction* instr,
    241                   int num_regs,
    242                   int operand_size,
    243                   intptr_t* start_address,
    244                   intptr_t* end_address);
    245   void HandleRList(Instruction* instr, bool load);
    246   void HandleVList(Instruction* inst);
    247   void SoftwareInterrupt(Instruction* instr);
    248 
    249   // Stop helper functions.
    250   inline bool isStopInstruction(Instruction* instr);
    251   inline bool isWatchedStop(uint32_t bkpt_code);
    252   inline bool isEnabledStop(uint32_t bkpt_code);
    253   inline void EnableStop(uint32_t bkpt_code);
    254   inline void DisableStop(uint32_t bkpt_code);
    255   inline void IncreaseStopCounter(uint32_t bkpt_code);
    256   void PrintStopInfo(uint32_t code);
    257 
    258   // Read and write memory.
    259   inline uint8_t ReadBU(int32_t addr);
    260   inline int8_t ReadB(int32_t addr);
    261   inline void WriteB(int32_t addr, uint8_t value);
    262   inline void WriteB(int32_t addr, int8_t value);
    263 
    264   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
    265   inline int16_t ReadH(int32_t addr, Instruction* instr);
    266   // Note: Overloaded on the sign of the value.
    267   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
    268   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
    269 
    270   inline int ReadW(int32_t addr, Instruction* instr);
    271   inline void WriteW(int32_t addr, int value, Instruction* instr);
    272 
    273   int32_t* ReadDW(int32_t addr);
    274   void WriteDW(int32_t addr, int32_t value1, int32_t value2);
    275 
    276   // Executing is handled based on the instruction type.
    277   // Both type 0 and type 1 rolled into one.
    278   void DecodeType01(Instruction* instr);
    279   void DecodeType2(Instruction* instr);
    280   void DecodeType3(Instruction* instr);
    281   void DecodeType4(Instruction* instr);
    282   void DecodeType5(Instruction* instr);
    283   void DecodeType6(Instruction* instr);
    284   void DecodeType7(Instruction* instr);
    285 
    286   // Support for VFP.
    287   void DecodeTypeVFP(Instruction* instr);
    288   void DecodeType6CoprocessorIns(Instruction* instr);
    289 
    290   void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr);
    291   void DecodeVCMP(Instruction* instr);
    292   void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr);
    293   void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr);
    294 
    295   // Executes one instruction.
    296   void InstructionDecode(Instruction* instr);
    297 
    298   // ICache.
    299   static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
    300   static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
    301                            int size);
    302   static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
    303 
    304   // Runtime call support.
    305   static void* RedirectExternalReference(
    306       void* external_function,
    307       v8::internal::ExternalReference::Type type);
    308 
    309   // For use in calls that take two double values, constructed from r0, r1, r2
    310   // and r3.
    311   void GetFpArgs(double* x, double* y);
    312   void SetFpResult(const double& result);
    313   void TrashCallerSaveRegisters();
    314 
    315   // Architecture state.
    316   // Saturating instructions require a Q flag to indicate saturation.
    317   // There is currently no way to read the CPSR directly, and thus read the Q
    318   // flag, so this is left unimplemented.
    319   int32_t registers_[16];
    320   bool n_flag_;
    321   bool z_flag_;
    322   bool c_flag_;
    323   bool v_flag_;
    324 
    325   // VFP architecture state.
    326   unsigned int vfp_register[num_s_registers];
    327   bool n_flag_FPSCR_;
    328   bool z_flag_FPSCR_;
    329   bool c_flag_FPSCR_;
    330   bool v_flag_FPSCR_;
    331 
    332   // VFP rounding mode. See ARM DDI 0406B Page A2-29.
    333   VFPRoundingMode FPSCR_rounding_mode_;
    334 
    335   // VFP FP exception flags architecture state.
    336   bool inv_op_vfp_flag_;
    337   bool div_zero_vfp_flag_;
    338   bool overflow_vfp_flag_;
    339   bool underflow_vfp_flag_;
    340   bool inexact_vfp_flag_;
    341 
    342   // Simulator support.
    343   char* stack_;
    344   bool pc_modified_;
    345   int icount_;
    346 
    347   // Icache simulation
    348   v8::internal::HashMap* i_cache_;
    349 
    350   // Registered breakpoints.
    351   Instruction* break_pc_;
    352   Instr break_instr_;
    353 
    354   v8::internal::Isolate* isolate_;
    355 
    356   // A stop is watched if its code is less than kNumOfWatchedStops.
    357   // Only watched stops support enabling/disabling and the counter feature.
    358   static const uint32_t kNumOfWatchedStops = 256;
    359 
    360   // Breakpoint is disabled if bit 31 is set.
    361   static const uint32_t kStopDisabledBit = 1 << 31;
    362 
    363   // A stop is enabled, meaning the simulator will stop when meeting the
    364   // instruction, if bit 31 of watched_stops[code].count is unset.
    365   // The value watched_stops[code].count & ~(1 << 31) indicates how many times
    366   // the breakpoint was hit or gone through.
    367   struct StopCountAndDesc {
    368     uint32_t count;
    369     char* desc;
    370   };
    371   StopCountAndDesc watched_stops[kNumOfWatchedStops];
    372 };
    373 
    374 
    375 // When running with the simulator transition into simulated execution at this
    376 // point.
    377 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
    378   reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
    379       FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
    380 
    381 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
    382   Simulator::current(Isolate::Current())->Call( \
    383       entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
    384 
    385 #define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
    386   try_catch_address == NULL ?                                                  \
    387       NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
    388 
    389 
    390 // The simulator has its own stack. Thus it has a different stack limit from
    391 // the C-based native code.  Setting the c_limit to indicate a very small
    392 // stack cause stack overflow errors, since the simulator ignores the input.
    393 // This is unlikely to be an issue in practice, though it might cause testing
    394 // trouble down the line.
    395 class SimulatorStack : public v8::internal::AllStatic {
    396  public:
    397   static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
    398     return Simulator::current(Isolate::Current())->StackLimit();
    399   }
    400 
    401   static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
    402     Simulator* sim = Simulator::current(Isolate::Current());
    403     return sim->PushAddress(try_catch_address);
    404   }
    405 
    406   static inline void UnregisterCTryCatch() {
    407     Simulator::current(Isolate::Current())->PopAddress();
    408   }
    409 };
    410 
    411 } }  // namespace v8::internal
    412 
    413 #endif  // !defined(USE_SIMULATOR)
    414 #endif  // V8_ARM_SIMULATOR_ARM_H_
    415