1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 // Copyright 2012 the V8 project authors. All rights reserved.
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 //       copyright notice, this list of conditions and the following
11 //       disclaimer in the documentation and/or other materials provided
12 //       with the distribution.
13 //     * Neither the name of Google Inc. nor the names of its
14 //       contributors may be used to endorse or promote products derived
15 //       from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifndef jit_arm_Simulator_arm_h
30 #define jit_arm_Simulator_arm_h
31 
32 #ifdef JS_SIMULATOR_ARM
33 
34 #include "jslock.h"
35 
36 #include "jit/arm/Architecture-arm.h"
37 #include "jit/arm/disasm/Disasm-arm.h"
38 #include "jit/IonTypes.h"
39 
40 namespace js {
41 namespace jit {
42 
43 class Simulator;
44 class Redirection;
45 class CachePage;
46 class AutoLockSimulator;
47 
48 // When the SingleStepCallback is called, the simulator is about to execute
49 // sim->get_pc() and the current machine state represents the completed
50 // execution of the previous pc.
51 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc);
52 
53 // VFP rounding modes. See ARM DDI 0406B Page A2-29.
54 enum VFPRoundingMode {
55     SimRN = 0 << 22,   // Round to Nearest.
56     SimRP = 1 << 22,   // Round towards Plus Infinity.
57     SimRM = 2 << 22,   // Round towards Minus Infinity.
58     SimRZ = 3 << 22,   // Round towards zero.
59 
60     // Aliases.
61     kRoundToNearest = SimRN,
62     kRoundToPlusInf = SimRP,
63     kRoundToMinusInf = SimRM,
64     kRoundToZero = SimRZ
65 };
66 
67 const uint32_t kVFPRoundingModeMask = 3 << 22;
68 
69 typedef int32_t Instr;
70 class SimInstruction;
71 
72 class Simulator
73 {
74     friend class Redirection;
75     friend class AutoLockSimulatorCache;
76 
77   public:
78     friend class ArmDebugger;
79     enum Register {
80         no_reg = -1,
81         r0 = 0, r1, r2, r3, r4, r5, r6, r7,
82         r8, r9, r10, r11, r12, r13, r14, r15,
83         num_registers,
84         sp = 13,
85         lr = 14,
86         pc = 15,
87         s0 = 0, s1, s2, s3, s4, s5, s6, s7,
88         s8, s9, s10, s11, s12, s13, s14, s15,
89         s16, s17, s18, s19, s20, s21, s22, s23,
90         s24, s25, s26, s27, s28, s29, s30, s31,
91         num_s_registers = 32,
92         d0 = 0, d1, d2, d3, d4, d5, d6, d7,
93         d8, d9, d10, d11, d12, d13, d14, d15,
94         d16, d17, d18, d19, d20, d21, d22, d23,
95         d24, d25, d26, d27, d28, d29, d30, d31,
96         num_d_registers = 32,
97         q0 = 0, q1, q2, q3, q4, q5, q6, q7,
98         q8, q9, q10, q11, q12, q13, q14, q15,
99         num_q_registers = 16
100     };
101 
102     // Returns nullptr on OOM.
103     static Simulator* Create();
104 
105     static void Destroy(Simulator* simulator);
106 
107     // Constructor/destructor are for internal use only; use the static methods above.
108     Simulator();
109     ~Simulator();
110 
111     // The currently executing Simulator instance. Potentially there can be one
112     // for each native thread.
113     static Simulator* Current();
114 
StackLimit()115     static inline uintptr_t StackLimit() {
116         return Simulator::Current()->stackLimit();
117     }
118 
119     uintptr_t* addressOfStackLimit();
120 
121     // Accessors for register state. Reading the pc value adheres to the ARM
122     // architecture specification and is off by a 8 from the currently executing
123     // instruction.
124     void set_register(int reg, int32_t value);
125     int32_t get_register(int reg) const;
126     double get_double_from_register_pair(int reg);
127     void set_register_pair_from_double(int reg, double* value);
128     void set_dw_register(int dreg, const int* dbl);
129 
130     // Support for VFP.
131     void get_d_register(int dreg, uint64_t* value);
132     void set_d_register(int dreg, const uint64_t* value);
133     void get_d_register(int dreg, uint32_t* value);
134     void set_d_register(int dreg, const uint32_t* value);
135     void get_q_register(int qreg, uint64_t* value);
136     void set_q_register(int qreg, const uint64_t* value);
137     void get_q_register(int qreg, uint32_t* value);
138     void set_q_register(int qreg, const uint32_t* value);
139     void set_s_register(int reg, unsigned int value);
140     unsigned int get_s_register(int reg) const;
141 
set_d_register_from_double(int dreg,const double & dbl)142     void set_d_register_from_double(int dreg, const double& dbl) {
143         setVFPRegister<double, 2>(dreg, dbl);
144     }
get_double_from_d_register(int dreg)145     double get_double_from_d_register(int dreg) {
146         return getFromVFPRegister<double, 2>(dreg);
147     }
set_s_register_from_float(int sreg,const float flt)148     void set_s_register_from_float(int sreg, const float flt) {
149         setVFPRegister<float, 1>(sreg, flt);
150     }
get_float_from_s_register(int sreg)151     float get_float_from_s_register(int sreg) {
152         return getFromVFPRegister<float, 1>(sreg);
153     }
set_s_register_from_sinteger(int sreg,const int sint)154     void set_s_register_from_sinteger(int sreg, const int sint) {
155         setVFPRegister<int, 1>(sreg, sint);
156     }
get_sinteger_from_s_register(int sreg)157     int get_sinteger_from_s_register(int sreg) {
158         return getFromVFPRegister<int, 1>(sreg);
159     }
160 
161     // Special case of set_register and get_register to access the raw PC value.
162     void set_pc(int32_t value);
163     int32_t get_pc() const;
164 
165     template <typename T>
get_pc_as()166     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
167 
set_resume_pc(void * value)168     void set_resume_pc(void* value) {
169         resume_pc_ = int32_t(value);
170     }
171 
172     void enable_single_stepping(SingleStepCallback cb, void* arg);
173     void disable_single_stepping();
174 
175     uintptr_t stackLimit() const;
176     bool overRecursed(uintptr_t newsp = 0) const;
177     bool overRecursedWithExtra(uint32_t extra) const;
178 
179     // Executes ARM instructions until the PC reaches end_sim_pc.
180     template<bool EnableStopSimAt>
181     void execute();
182 
183     // Sets up the simulator state and grabs the result on return.
184     int32_t call(uint8_t* entry, int argument_count, ...);
185 
186     // Debugger input.
187     void setLastDebuggerInput(char* input);
lastDebuggerInput()188     char* lastDebuggerInput() { return lastDebuggerInput_; }
189 
190     // Returns true if pc register contains one of the 'special_values' defined
191     // below (bad_lr, end_sim_pc).
192     bool has_bad_pc() const;
193 
194   private:
195     enum special_values {
196         // Known bad pc value to ensure that the simulator does not execute
197         // without being properly setup.
198         bad_lr = -1,
199         // A pc value used to signal the simulator to stop execution. Generally
200         // the lr is set to this value on transition from native C code to
201         // simulated execution, so that the simulator can "return" to the native
202         // C code.
203         end_sim_pc = -2
204     };
205 
206     bool init();
207 
208     // Checks if the current instruction should be executed based on its
209     // condition bits.
210     inline bool conditionallyExecute(SimInstruction* instr);
211 
212     // Helper functions to set the conditional flags in the architecture state.
213     void setNZFlags(int32_t val);
214     void setCFlag(bool val);
215     void setVFlag(bool val);
216     bool carryFrom(int32_t left, int32_t right, int32_t carry = 0);
217     bool borrowFrom(int32_t left, int32_t right);
218     bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition);
219 
getCarry()220     inline int getCarry() { return c_flag_ ? 1 : 0; };
221 
222     // Support for VFP.
223     void compute_FPSCR_Flags(double val1, double val2);
224     void copy_FPSCR_to_APSR();
225     inline double canonicalizeNaN(double value);
226 
227     // Helper functions to decode common "addressing" modes
228     int32_t getShiftRm(SimInstruction* instr, bool* carry_out);
229     int32_t getImm(SimInstruction* instr, bool* carry_out);
230     int32_t processPU(SimInstruction* instr, int num_regs, int operand_size,
231                       intptr_t* start_address, intptr_t* end_address);
232     void handleRList(SimInstruction* instr, bool load);
233     void handleVList(SimInstruction* inst);
234     void softwareInterrupt(SimInstruction* instr);
235 
236     // Stop helper functions.
237     inline bool isStopInstruction(SimInstruction* 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     inline uint8_t readBU(int32_t addr);
247     inline int8_t readB(int32_t addr);
248     inline void writeB(int32_t addr, uint8_t value);
249     inline void writeB(int32_t addr, int8_t value);
250 
251     inline uint8_t readExBU(int32_t addr);
252     inline int32_t writeExB(int32_t addr, uint8_t value);
253 
254     inline uint16_t readHU(int32_t addr, SimInstruction* instr);
255     inline int16_t readH(int32_t addr, SimInstruction* instr);
256     // Note: Overloaded on the sign of the value.
257     inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr);
258     inline void writeH(int32_t addr, int16_t value, SimInstruction* instr);
259 
260     inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
261     inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
262 
263     inline int readW(int32_t addr, SimInstruction* instr);
264     inline void writeW(int32_t addr, int value, SimInstruction* instr);
265 
266     inline int readExW(int32_t addr, SimInstruction* instr);
267     inline int writeExW(int32_t addr, int value, SimInstruction* instr);
268 
269     int32_t* readDW(int32_t addr);
270     void writeDW(int32_t addr, int32_t value1, int32_t value2);
271 
272     int32_t readExDW(int32_t addr, int32_t* hibits);
273     int32_t writeExDW(int32_t addr, int32_t value1, int32_t value2);
274 
275     // Executing is handled based on the instruction type.
276     // Both type 0 and type 1 rolled into one.
277     void decodeType01(SimInstruction* instr);
278     void decodeType2(SimInstruction* instr);
279     void decodeType3(SimInstruction* instr);
280     void decodeType4(SimInstruction* instr);
281     void decodeType5(SimInstruction* instr);
282     void decodeType6(SimInstruction* instr);
283     void decodeType7(SimInstruction* instr);
284 
285     // Support for VFP.
286     void decodeTypeVFP(SimInstruction* instr);
287     void decodeType6CoprocessorIns(SimInstruction* instr);
288     void decodeSpecialCondition(SimInstruction* instr);
289 
290     void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction* instr);
291     void decodeVCMP(SimInstruction* instr);
292     void decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr);
293     void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction* instr);
294     void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction* instr);
295 
296     // Support for some system functions.
297     void decodeType7CoprocessorIns(SimInstruction* instr);
298 
299     // Executes one instruction.
300     void instructionDecode(SimInstruction* instr);
301 
302   public:
303     static bool ICacheCheckingEnabled;
304     static void FlushICache(void* start, size_t size);
305 
306     static int64_t StopSimAt;
307 
308     // For testing the MoveResolver code, a MoveResolver is set up, and
309     // the VFP registers are loaded with pre-determined values,
310     // then the sequence of code is simulated.  In order to test this with the
311     // simulator, the callee-saved registers can't be trashed. This flag
312     // disables that feature.
313     bool skipCalleeSavedRegsCheck;
314 
315     // Runtime call support.
316     static void* RedirectNativeFunction(void* nativeFunction, ABIFunctionType type);
317 
318   private:
319     // Handle arguments and return value for runtime FP functions.
320     void getFpArgs(double* x, double* y, int32_t* z);
321     void getFpFromStack(int32_t* stack, double* x1);
322     void setCallResultDouble(double result);
323     void setCallResultFloat(float result);
324     void setCallResult(int64_t res);
325     void scratchVolatileRegisters(bool scratchFloat = true);
326 
327     template<class ReturnType, int register_size>
328     ReturnType getFromVFPRegister(int reg_index);
329 
330     template<class InputType, int register_size>
331     void setVFPRegister(int reg_index, const InputType& value);
332 
333     void callInternal(uint8_t* entry);
334 
335     // Architecture state.
336     // Saturating instructions require a Q flag to indicate saturation.
337     // There is currently no way to read the CPSR directly, and thus read the Q
338     // flag, so this is left unimplemented.
339     int32_t registers_[16];
340     bool n_flag_;
341     bool z_flag_;
342     bool c_flag_;
343     bool v_flag_;
344 
345     // VFP architecture state.
346     uint32_t vfp_registers_[num_d_registers * 2];
347     bool n_flag_FPSCR_;
348     bool z_flag_FPSCR_;
349     bool c_flag_FPSCR_;
350     bool v_flag_FPSCR_;
351 
352     // VFP rounding mode. See ARM DDI 0406B Page A2-29.
353     VFPRoundingMode FPSCR_rounding_mode_;
354     bool FPSCR_default_NaN_mode_;
355 
356     // VFP FP exception flags architecture state.
357     bool inv_op_vfp_flag_;
358     bool div_zero_vfp_flag_;
359     bool overflow_vfp_flag_;
360     bool underflow_vfp_flag_;
361     bool inexact_vfp_flag_;
362 
363     // Simulator support.
364     char* stack_;
365     uintptr_t stackLimit_;
366     bool pc_modified_;
367     int64_t icount_;
368 
369     int32_t resume_pc_;
370 
371     // Debugger input.
372     char* lastDebuggerInput_;
373 
374     // Registered breakpoints.
375     SimInstruction* break_pc_;
376     Instr break_instr_;
377 
378     // Single-stepping support
379     bool single_stepping_;
380     SingleStepCallback single_step_callback_;
381     void* single_step_callback_arg_;
382 
383     // A stop is watched if its code is less than kNumOfWatchedStops.
384     // Only watched stops support enabling/disabling and the counter feature.
385     static const uint32_t kNumOfWatchedStops = 256;
386 
387     // Breakpoint is disabled if bit 31 is set.
388     static const uint32_t kStopDisabledBit = 1 << 31;
389 
390     // A stop is enabled, meaning the simulator will stop when meeting the
391     // instruction, if bit 31 of watched_stops_[code].count is unset.
392     // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
393     // the breakpoint was hit or gone through.
394     struct StopCountAndDesc {
395         uint32_t count;
396         char* desc;
397     };
398     StopCountAndDesc watched_stops_[kNumOfWatchedStops];
399 
400   public:
icount()401     int64_t icount() {
402         return icount_;
403     }
404 
405   private:
406     // ICache checking.
407     struct ICacheHasher {
408         typedef void* Key;
409         typedef void* Lookup;
410         static HashNumber hash(const Lookup& l);
411         static bool match(const Key& k, const Lookup& l);
412     };
413 
414   public:
415     typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
416 
417   private:
418     // This lock creates a critical section around 'redirection_' and
419     // 'icache_', which are referenced both by the execution engine
420     // and by the off-thread compiler (see Redirection::Get in the cpp file).
421     PRLock* cacheLock_;
422 #ifdef DEBUG
423     PRThread* cacheLockHolder_;
424 #endif
425 
426     Redirection* redirection_;
427     ICacheMap icache_;
428 
429   public:
icache()430     ICacheMap& icache() {
431         // Technically we need the lock to access the innards of the
432         // icache, not to take its address, but the latter condition
433         // serves as a useful complement to the former.
434         MOZ_ASSERT(cacheLockHolder_);
435         return icache_;
436     }
437 
redirection()438     Redirection* redirection() const {
439         MOZ_ASSERT(cacheLockHolder_);
440         return redirection_;
441     }
442 
setRedirection(js::jit::Redirection * redirection)443     void setRedirection(js::jit::Redirection* redirection) {
444         MOZ_ASSERT(cacheLockHolder_);
445         redirection_ = redirection;
446     }
447 
448   private:
449     // Exclusive access monitor
450     void exclusiveMonitorSet(uint64_t value);
451     uint64_t exclusiveMonitorGetAndClear(bool* held);
452     void exclusiveMonitorClear();
453 
454     bool exclusiveMonitorHeld_;
455     uint64_t exclusiveMonitor_;
456 };
457 
458 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror)             \
459     JS_BEGIN_MACRO                                                              \
460         if (cx->runtime()->simulator()->overRecursedWithExtra(extra)) {         \
461             js::ReportOverRecursed(cx);                                         \
462             onerror;                                                            \
463         }                                                                       \
464     JS_END_MACRO
465 
466 } // namespace jit
467 } // namespace js
468 
469 #endif /* JS_SIMULATOR_ARM */
470 
471 #endif /* jit_arm_Simulator_arm_h */
472