1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 // Copyright 2011 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_mips32_Simulator_mips32_h
30 #define jit_mips32_Simulator_mips32_h
31 
32 #ifdef JS_SIMULATOR_MIPS32
33 
34 #include "jit/IonTypes.h"
35 #include "threading/Thread.h"
36 #include "vm/MutexIDs.h"
37 
38 namespace js {
39 namespace jit {
40 
41 class Simulator;
42 class Redirection;
43 class CachePage;
44 class AutoLockSimulator;
45 
46 const intptr_t kPointerAlignment = 4;
47 const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
48 
49 const intptr_t kDoubleAlignment = 8;
50 const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1;
51 
52 
53 // Number of general purpose registers.
54 const int kNumRegisters = 32;
55 
56 // In the simulator, the PC register is simulated as the 34th register.
57 const int kPCRegister = 34;
58 
59 // Number coprocessor registers.
60 const int kNumFPURegisters = 32;
61 
62 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
63 const int kFCSRRegister = 31;
64 const int kInvalidFPUControlRegister = -1;
65 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
66 
67 // FCSR constants.
68 const uint32_t kFCSRInexactFlagBit = 2;
69 const uint32_t kFCSRUnderflowFlagBit = 3;
70 const uint32_t kFCSROverflowFlagBit = 4;
71 const uint32_t kFCSRDivideByZeroFlagBit = 5;
72 const uint32_t kFCSRInvalidOpFlagBit = 6;
73 
74 const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
75 const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
76 const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
77 const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
78 const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
79 
80 const uint32_t kFCSRFlagMask =
81     kFCSRInexactFlagMask |
82     kFCSRUnderflowFlagMask |
83     kFCSROverflowFlagMask |
84     kFCSRDivideByZeroFlagMask |
85     kFCSRInvalidOpFlagMask;
86 
87 const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask;
88 
89 // On MIPS Simulator breakpoints can have different codes:
90 // - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints,
91 //   the simulator will run through them and print the registers.
92 // - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop()
93 //   instructions (see Assembler::stop()).
94 // - Breaks larger than kMaxStopCode are simple breaks, dropping you into the
95 //   debugger.
96 const uint32_t kMaxWatchpointCode = 31;
97 const uint32_t kMaxStopCode = 127;
98 
99 // -----------------------------------------------------------------------------
100 // Utility functions
101 
102 typedef uint32_t Instr;
103 class SimInstruction;
104 
105 class Simulator {
106     friend class Redirection;
107     friend class MipsDebugger;
108     friend class AutoLockSimulatorCache;
109   public:
110 
111     // Registers are declared in order. See "See MIPS Run Linux" chapter 2.
112     enum Register {
113         no_reg = -1,
114         zero_reg = 0,
115         at,
116         v0, v1,
117         a0, a1, a2, a3,
118         t0, t1, t2, t3, t4, t5, t6, t7,
119         s0, s1, s2, s3, s4, s5, s6, s7,
120         t8, t9,
121         k0, k1,
122         gp,
123         sp,
124         s8,
125         ra,
126         // LO, HI, and pc.
127         LO,
128         HI,
129         pc,   // pc must be the last register.
130         kNumSimuRegisters,
131         // aliases
132         fp = s8
133     };
134 
135     // Coprocessor registers.
136     enum FPURegister {
137         f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
138         f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
139         f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
140         f26, f27, f28, f29, f30, f31,
141         kNumFPURegisters
142     };
143 
144     // Returns nullptr on OOM.
145     static Simulator* Create(JSContext* cx);
146 
147     static void Destroy(Simulator* simulator);
148 
149     // Constructor/destructor are for internal use only; use the static methods above.
150     Simulator();
151     ~Simulator();
152 
153     // The currently executing Simulator instance. Potentially there can be one
154     // for each native thread.
155     static Simulator* Current();
156 
StackLimit()157     static inline uintptr_t StackLimit() {
158         return Simulator::Current()->stackLimit();
159     }
160 
161     uintptr_t* addressOfStackLimit();
162 
163     // Accessors for register state. Reading the pc value adheres to the MIPS
164     // architecture specification and is off by a 8 from the currently executing
165     // instruction.
166     void setRegister(int reg, int32_t value);
167     int32_t getRegister(int reg) const;
168     double getDoubleFromRegisterPair(int reg);
169     // Same for FPURegisters.
170     void setFpuRegister(int fpureg, int32_t value);
171     void setFpuRegisterFloat(int fpureg, float value);
172     void setFpuRegisterFloat(int fpureg, int64_t value);
173     void setFpuRegisterDouble(int fpureg, double value);
174     void setFpuRegisterDouble(int fpureg, int64_t value);
175     int32_t getFpuRegister(int fpureg) const;
176     int64_t getFpuRegisterLong(int fpureg) const;
177     float getFpuRegisterFloat(int fpureg) const;
178     double getFpuRegisterDouble(int fpureg) const;
179     void setFCSRBit(uint32_t cc, bool value);
180     bool testFCSRBit(uint32_t cc);
181     bool setFCSRRoundError(double original, double rounded);
182 
183     // Special case of set_register and get_register to access the raw PC value.
184     void set_pc(int32_t value);
185     int32_t get_pc() const;
186 
187     template <typename T>
get_pc_as()188     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
189 
set_resume_pc(void * value)190     void set_resume_pc(void* value) {
191         resume_pc_ = int32_t(value);
192     }
193 
194     // Accessor to the internal simulator stack area.
195     uintptr_t stackLimit() const;
196     bool overRecursed(uintptr_t newsp = 0) const;
197     bool overRecursedWithExtra(uint32_t extra) const;
198 
199     // Executes MIPS instructions until the PC reaches end_sim_pc.
200     template<bool enableStopSimAt>
201     void execute();
202 
203     // Sets up the simulator state and grabs the result on return.
204     int32_t call(uint8_t* entry, int argument_count, ...);
205 
206     // Push an address onto the JS stack.
207     uintptr_t pushAddress(uintptr_t address);
208 
209     // Pop an address from the JS stack.
210     uintptr_t popAddress();
211 
212     // Debugger input.
213     void setLastDebuggerInput(char* input);
lastDebuggerInput()214     char* lastDebuggerInput() { return lastDebuggerInput_; }
215     // ICache checking.
216     static void FlushICache(void* start, size_t size);
217 
218     // Returns true if pc register contains one of the 'SpecialValues' defined
219     // below (bad_ra, end_sim_pc).
220     bool has_bad_pc() const;
221 
222   private:
223     enum SpecialValues {
224         // Known bad pc value to ensure that the simulator does not execute
225         // without being properly setup.
226         bad_ra = -1,
227         // A pc value used to signal the simulator to stop execution.  Generally
228         // the ra is set to this value on transition from native C code to
229         // simulated execution, so that the simulator can "return" to the native
230         // C code.
231         end_sim_pc = -2,
232         // Unpredictable value.
233         Unpredictable = 0xbadbeaf
234     };
235 
236     bool init();
237 
238     // Unsupported instructions use Format to print an error and stop execution.
239     void format(SimInstruction* instr, const char* format);
240 
241     // Read and write memory.
242     inline uint32_t readBU(uint32_t addr);
243     inline int32_t readB(uint32_t addr);
244     inline void writeB(uint32_t addr, uint8_t value);
245     inline void writeB(uint32_t addr, int8_t value);
246 
247     inline uint16_t readHU(uint32_t addr, SimInstruction* instr);
248     inline int16_t readH(uint32_t addr, SimInstruction* instr);
249     // Note: Overloaded on the sign of the value.
250     inline void writeH(uint32_t addr, uint16_t value, SimInstruction* instr);
251     inline void writeH(uint32_t addr, int16_t value, SimInstruction* instr);
252 
253     inline int readW(uint32_t addr, SimInstruction* instr);
254     inline void writeW(uint32_t addr, int value, SimInstruction* instr);
255 
256     inline double readD(uint32_t addr, SimInstruction* instr);
257     inline void writeD(uint32_t addr, double value, SimInstruction* instr);
258 
259     // Executing is handled based on the instruction type.
260     void decodeTypeRegister(SimInstruction* instr);
261 
262     // Helper function for decodeTypeRegister.
263     void configureTypeRegister(SimInstruction* instr,
264                                int32_t& alu_out,
265                                int64_t& i64hilo,
266                                uint64_t& u64hilo,
267                                int32_t& next_pc,
268                                int32_t& return_addr_reg,
269                                bool& do_interrupt);
270 
271     void decodeTypeImmediate(SimInstruction* instr);
272     void decodeTypeJump(SimInstruction* instr);
273 
274     // Used for breakpoints and traps.
275     void softwareInterrupt(SimInstruction* instr);
276 
277     // Stop helper functions.
278     bool isWatchpoint(uint32_t code);
279     void printWatchpoint(uint32_t code);
280     void handleStop(uint32_t code, SimInstruction* instr);
281     bool isStopInstruction(SimInstruction* instr);
282     bool isEnabledStop(uint32_t code);
283     void enableStop(uint32_t code);
284     void disableStop(uint32_t code);
285     void increaseStopCounter(uint32_t code);
286     void printStopInfo(uint32_t code);
287 
288 
289     // Executes one instruction.
290     void instructionDecode(SimInstruction* instr);
291     // Execute one instruction placed in a branch delay slot.
292     void branchDelayInstructionDecode(SimInstruction* instr);
293 
294   public:
295     static bool ICacheCheckingEnabled;
296 
297     static int StopSimAt;
298 
299     // Runtime call support.
300     static void* RedirectNativeFunction(void* nativeFunction, ABIFunctionType type);
301 
302   private:
303     enum Exception {
304         kNone,
305         kIntegerOverflow,
306         kIntegerUnderflow,
307         kDivideByZero,
308         kNumExceptions
309     };
310     int16_t exceptions[kNumExceptions];
311 
312     // Exceptions.
313     void signalExceptions();
314 
315     // Handle arguments and return value for runtime FP functions.
316     void getFpArgs(double* x, double* y, int32_t* z);
317     void getFpFromStack(int32_t* stack, double* x);
318 
319     void setCallResultDouble(double result);
320     void setCallResultFloat(float result);
321     void setCallResult(int64_t res);
322 
323     void callInternal(uint8_t* entry);
324 
325     // Architecture state.
326     // Registers.
327     int32_t registers_[kNumSimuRegisters];
328     // Coprocessor Registers.
329     int32_t FPUregisters_[kNumFPURegisters];
330     // FPU control register.
331     uint32_t FCSR_;
332 
333     // Simulator support.
334     char* stack_;
335     uintptr_t stackLimit_;
336     bool pc_modified_;
337     int icount_;
338     int break_count_;
339 
340     int32_t resume_pc_;
341 
342     // Debugger input.
343     char* lastDebuggerInput_;
344 
345     // Registered breakpoints.
346     SimInstruction* break_pc_;
347     Instr break_instr_;
348 
349     // A stop is watched if its code is less than kNumOfWatchedStops.
350     // Only watched stops support enabling/disabling and the counter feature.
351     static const uint32_t kNumOfWatchedStops = 256;
352 
353 
354     // Stop is disabled if bit 31 is set.
355     static const uint32_t kStopDisabledBit = 1U << 31;
356 
357     // A stop is enabled, meaning the simulator will stop when meeting the
358     // instruction, if bit 31 of watchedStops_[code].count is unset.
359     // The value watchedStops_[code].count & ~(1 << 31) indicates how many times
360     // the breakpoint was hit or gone through.
361     struct StopCountAndDesc {
362         uint32_t count_;
363         char* desc_;
364     };
365     StopCountAndDesc watchedStops_[kNumOfWatchedStops];
366 
367   private:
368     // ICache checking.
369     struct ICacheHasher {
370         typedef void* Key;
371         typedef void* Lookup;
372         static HashNumber hash(const Lookup& l);
373         static bool match(const Key& k, const Lookup& l);
374     };
375 
376   public:
377     typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
378 
379   private:
380     // This lock creates a critical section around 'redirection_' and
381     // 'icache_', which are referenced both by the execution engine
382     // and by the off-thread compiler (see Redirection::Get in the cpp file).
383     Mutex cacheLock_;
384 #ifdef DEBUG
385     mozilla::Maybe<Thread::Id> cacheLockHolder_;
386 #endif
387 
388     Redirection* redirection_;
389     ICacheMap icache_;
390 
391   public:
icache()392     ICacheMap& icache() {
393         // Technically we need the lock to access the innards of the
394         // icache, not to take its address, but the latter condition
395         // serves as a useful complement to the former.
396         MOZ_ASSERT(cacheLockHolder_.isSome());
397         return icache_;
398     }
399 
redirection()400     Redirection* redirection() const {
401         MOZ_ASSERT(cacheLockHolder_.isSome());
402         return redirection_;
403     }
404 
setRedirection(js::jit::Redirection * redirection)405     void setRedirection(js::jit::Redirection* redirection) {
406         MOZ_ASSERT(cacheLockHolder_.isSome());
407         redirection_ = redirection;
408     }
409 };
410 
411 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror)             \
412     JS_BEGIN_MACRO                                                              \
413         if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) {       \
414             js::ReportOverRecursed(cx);                                         \
415             onerror;                                                            \
416         }                                                                       \
417     JS_END_MACRO
418 
419 } // namespace jit
420 } // namespace js
421 
422 #endif /* JS_SIMULATOR_MIPS32 */
423 
424 #endif /* jit_mips32_Simulator_mips32_h */
425