1 // Copyright 2011 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 MIPS instructions if we are not generating a native
7 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
8 // on 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 MIPS HW platform.
12 
13 #ifndef V8_MIPS_SIMULATOR_MIPS_H_
14 #define V8_MIPS_SIMULATOR_MIPS_H_
15 
16 #include "src/allocation.h"
17 #include "src/mips/constants-mips.h"
18 
19 #if !defined(USE_SIMULATOR)
20 // Running without a simulator on a native mips platform.
21 
22 namespace v8 {
23 namespace internal {
24 
25 // When running without a simulator we call the entry directly.
26 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
27   entry(p0, p1, p2, p3, p4)
28 
29 typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
30                                    void*, int*, int, Address, int, Isolate*);
31 
32 
33 // Call the generated regexp code directly. The code at the entry address
34 // should act as a function matching the type arm_regexp_matcher.
35 // The fifth argument is a dummy that reserves the space used for
36 // the return address added by the ExitFrame in native calls.
37 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
38                                    p7, p8)                                     \
39   (FUNCTION_CAST<mips_regexp_matcher>(entry)(p0, p1, p2, p3, NULL, p4, p5, p6, \
40                                              p7, p8))
41 
42 // The stack limit beyond which we will throw stack overflow errors in
43 // generated code. Because generated code on mips uses the C stack, we
44 // just use the C stack limit.
45 class SimulatorStack : public v8::internal::AllStatic {
46  public:
JsLimitFromCLimit(Isolate * isolate,uintptr_t c_limit)47   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
48                                             uintptr_t c_limit) {
49     return c_limit;
50   }
51 
RegisterCTryCatch(Isolate * isolate,uintptr_t try_catch_address)52   static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
53                                             uintptr_t try_catch_address) {
54     USE(isolate);
55     return try_catch_address;
56   }
57 
UnregisterCTryCatch(Isolate * isolate)58   static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); }
59 };
60 
61 }  // namespace internal
62 }  // namespace v8
63 
64 // Calculated the stack limit beyond which we will throw stack overflow errors.
65 // This macro must be called from a C++ method. It relies on being able to take
66 // the address of "this" to get a value on the current execution stack and then
67 // calculates the stack limit based on that value.
68 // NOTE: The check for overflow is not safe as there is no guarantee that the
69 // running thread has its stack in all memory up to address 0x00000000.
70 #define GENERATED_CODE_STACK_LIMIT(limit) \
71   (reinterpret_cast<uintptr_t>(this) >= limit ? \
72       reinterpret_cast<uintptr_t>(this) - limit : 0)
73 
74 #else  // !defined(USE_SIMULATOR)
75 // Running with a simulator.
76 
77 #include "src/assembler.h"
78 #include "src/base/hashmap.h"
79 
80 namespace v8 {
81 namespace internal {
82 
83 // -----------------------------------------------------------------------------
84 // Utility functions
85 
86 class CachePage {
87  public:
88   static const int LINE_VALID = 0;
89   static const int LINE_INVALID = 1;
90 
91   static const int kPageShift = 12;
92   static const int kPageSize = 1 << kPageShift;
93   static const int kPageMask = kPageSize - 1;
94   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
95   static const int kLineLength = 1 << kLineShift;
96   static const int kLineMask = kLineLength - 1;
97 
CachePage()98   CachePage() {
99     memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
100   }
101 
ValidityByte(int offset)102   char* ValidityByte(int offset) {
103     return &validity_map_[offset >> kLineShift];
104   }
105 
CachedData(int offset)106   char* CachedData(int offset) {
107     return &data_[offset];
108   }
109 
110  private:
111   char data_[kPageSize];   // The cached data.
112   static const int kValidityMapSize = kPageSize >> kLineShift;
113   char validity_map_[kValidityMapSize];  // One byte per line.
114 };
115 
116 class SimInstructionBase : public InstructionBase {
117  public:
InstructionType()118   Type InstructionType() const { return type_; }
instr()119   inline Instruction* instr() const { return instr_; }
operand()120   inline int32_t operand() const { return operand_; }
121 
122  protected:
SimInstructionBase()123   SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
SimInstructionBase(Instruction * instr)124   explicit SimInstructionBase(Instruction* instr) {}
125 
126   int32_t operand_;
127   Instruction* instr_;
128   Type type_;
129 
130  private:
131   DISALLOW_ASSIGN(SimInstructionBase);
132 };
133 
134 class SimInstruction : public InstructionGetters<SimInstructionBase> {
135  public:
SimInstruction()136   SimInstruction() {}
137 
SimInstruction(Instruction * instr)138   explicit SimInstruction(Instruction* instr) { *this = instr; }
139 
140   SimInstruction& operator=(Instruction* instr) {
141     operand_ = *reinterpret_cast<const int32_t*>(instr);
142     instr_ = instr;
143     type_ = InstructionBase::InstructionType();
144     DCHECK(reinterpret_cast<void*>(&operand_) == this);
145     return *this;
146   }
147 };
148 
149 class Simulator {
150  public:
151   friend class MipsDebugger;
152 
153   // Registers are declared in order. See SMRL chapter 2.
154   enum Register {
155     no_reg = -1,
156     zero_reg = 0,
157     at,
158     v0, v1,
159     a0, a1, a2, a3,
160     t0, t1, t2, t3, t4, t5, t6, t7,
161     s0, s1, s2, s3, s4, s5, s6, s7,
162     t8, t9,
163     k0, k1,
164     gp,
165     sp,
166     s8,
167     ra,
168     // LO, HI, and pc.
169     LO,
170     HI,
171     pc,   // pc must be the last register.
172     kNumSimuRegisters,
173     // aliases
174     fp = s8
175   };
176 
177   // Coprocessor registers.
178   // Generated code will always use doubles. So we will only use even registers.
179   enum FPURegister {
180     f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
181     f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
182     f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
183     f26, f27, f28, f29, f30, f31,
184     kNumFPURegisters
185   };
186 
187   explicit Simulator(Isolate* isolate);
188   ~Simulator();
189 
190   // The currently executing Simulator instance. Potentially there can be one
191   // for each native thread.
192   static Simulator* current(v8::internal::Isolate* isolate);
193 
194   // Accessors for register state. Reading the pc value adheres to the MIPS
195   // architecture specification and is off by a 8 from the currently executing
196   // instruction.
197   void set_register(int reg, int32_t value);
198   void set_dw_register(int dreg, const int* dbl);
199   int32_t get_register(int reg) const;
200   double get_double_from_register_pair(int reg);
201   // Same for FPURegisters.
202   void set_fpu_register(int fpureg, int64_t value);
203   void set_fpu_register_word(int fpureg, int32_t value);
204   void set_fpu_register_hi_word(int fpureg, int32_t value);
205   void set_fpu_register_float(int fpureg, float value);
206   void set_fpu_register_double(int fpureg, double value);
207   void set_fpu_register_invalid_result64(float original, float rounded);
208   void set_fpu_register_invalid_result(float original, float rounded);
209   void set_fpu_register_word_invalid_result(float original, float rounded);
210   void set_fpu_register_invalid_result64(double original, double rounded);
211   void set_fpu_register_invalid_result(double original, double rounded);
212   void set_fpu_register_word_invalid_result(double original, double rounded);
213   int64_t get_fpu_register(int fpureg) const;
214   int32_t get_fpu_register_word(int fpureg) const;
215   int32_t get_fpu_register_signed_word(int fpureg) const;
216   int32_t get_fpu_register_hi_word(int fpureg) const;
217   float get_fpu_register_float(int fpureg) const;
218   double get_fpu_register_double(int fpureg) const;
219   void set_fcsr_bit(uint32_t cc, bool value);
220   bool test_fcsr_bit(uint32_t cc);
221   void set_fcsr_rounding_mode(FPURoundingMode mode);
222   unsigned int get_fcsr_rounding_mode();
223   bool set_fcsr_round_error(double original, double rounded);
224   bool set_fcsr_round_error(float original, float rounded);
225   bool set_fcsr_round64_error(double original, double rounded);
226   bool set_fcsr_round64_error(float original, float rounded);
227   void round_according_to_fcsr(double toRound, double& rounded,
228                                int32_t& rounded_int, double fs);
229   void round_according_to_fcsr(float toRound, float& rounded,
230                                int32_t& rounded_int, float fs);
231   void round64_according_to_fcsr(double toRound, double& rounded,
232                                  int64_t& rounded_int, double fs);
233   void round64_according_to_fcsr(float toRound, float& rounded,
234                                  int64_t& rounded_int, float fs);
235   // Special case of set_register and get_register to access the raw PC value.
236   void set_pc(int32_t value);
237   int32_t get_pc() const;
238 
get_sp()239   Address get_sp() const {
240     return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
241   }
242 
243   // Accessor to the internal simulator stack area.
244   uintptr_t StackLimit(uintptr_t c_limit) const;
245 
246   // Executes MIPS instructions until the PC reaches end_sim_pc.
247   void Execute();
248 
249   // Call on program start.
250   static void Initialize(Isolate* isolate);
251 
252   static void TearDown(base::CustomMatcherHashMap* i_cache, Redirection* first);
253 
254   // V8 generally calls into generated JS code with 5 parameters and into
255   // generated RegExp code with 7 parameters. This is a convenience function,
256   // which sets up the simulator state and grabs the result on return.
257   int32_t Call(byte* entry, int argument_count, ...);
258   // Alternative: call a 2-argument double function.
259   double CallFP(byte* entry, double d0, double d1);
260 
261   // Push an address onto the JS stack.
262   uintptr_t PushAddress(uintptr_t address);
263 
264   // Pop an address from the JS stack.
265   uintptr_t PopAddress();
266 
267   // Debugger input.
268   void set_last_debugger_input(char* input);
last_debugger_input()269   char* last_debugger_input() { return last_debugger_input_; }
270 
271   // ICache checking.
272   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
273                           size_t size);
274 
275   // Returns true if pc register contains one of the 'special_values' defined
276   // below (bad_ra, end_sim_pc).
277   bool has_bad_pc() const;
278 
279  private:
280   enum special_values {
281     // Known bad pc value to ensure that the simulator does not execute
282     // without being properly setup.
283     bad_ra = -1,
284     // A pc value used to signal the simulator to stop execution.  Generally
285     // the ra is set to this value on transition from native C code to
286     // simulated execution, so that the simulator can "return" to the native
287     // C code.
288     end_sim_pc = -2,
289     // Unpredictable value.
290     Unpredictable = 0xbadbeaf
291   };
292 
293   // Unsupported instructions use Format to print an error and stop execution.
294   void Format(Instruction* instr, const char* format);
295 
296   // Read and write memory.
297   inline uint32_t ReadBU(int32_t addr);
298   inline int32_t ReadB(int32_t addr);
299   inline void WriteB(int32_t addr, uint8_t value);
300   inline void WriteB(int32_t addr, int8_t value);
301 
302   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
303   inline int16_t ReadH(int32_t addr, Instruction* instr);
304   // Note: Overloaded on the sign of the value.
305   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
306   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
307 
308   inline int ReadW(int32_t addr, Instruction* instr);
309   inline void WriteW(int32_t addr, int value, Instruction* instr);
310 
311   inline double ReadD(int32_t addr, Instruction* instr);
312   inline void WriteD(int32_t addr, double value, Instruction* instr);
313 
314   // Helpers for data value tracing.
315   enum TraceType {
316     BYTE,
317     HALF,
318     WORD
319     // DWORD,
320     // DFLOAT - Floats may have printing issues due to paired lwc1's
321   };
322 
323   void TraceRegWr(int32_t value);
324   void TraceMemWr(int32_t addr, int32_t value, TraceType t);
325   void TraceMemRd(int32_t addr, int32_t value);
326   EmbeddedVector<char, 128> trace_buf_;
327 
328   // Operations depending on endianness.
329   // Get Double Higher / Lower word.
330   inline int32_t GetDoubleHIW(double* addr);
331   inline int32_t GetDoubleLOW(double* addr);
332   // Set Double Higher / Lower word.
333   inline int32_t SetDoubleHIW(double* addr);
334   inline int32_t SetDoubleLOW(double* addr);
335 
336   SimInstruction instr_;
337 
338   // Executing is handled based on the instruction type.
339   void DecodeTypeRegister();
340 
341   // Functions called from DecodeTypeRegister.
342   void DecodeTypeRegisterCOP1();
343 
344   void DecodeTypeRegisterCOP1X();
345 
346   void DecodeTypeRegisterSPECIAL();
347 
348   void DecodeTypeRegisterSPECIAL2();
349 
350   void DecodeTypeRegisterSPECIAL3();
351 
352   // Called from DecodeTypeRegisterCOP1.
353   void DecodeTypeRegisterSRsType();
354 
355   void DecodeTypeRegisterDRsType();
356 
357   void DecodeTypeRegisterWRsType();
358 
359   void DecodeTypeRegisterLRsType();
360 
rs_reg()361   inline int32_t rs_reg() const { return instr_.RsValue(); }
rs()362   inline int32_t rs() const { return get_register(rs_reg()); }
rs_u()363   inline uint32_t rs_u() const {
364     return static_cast<uint32_t>(get_register(rs_reg()));
365   }
rt_reg()366   inline int32_t rt_reg() const { return instr_.RtValue(); }
rt()367   inline int32_t rt() const { return get_register(rt_reg()); }
rt_u()368   inline uint32_t rt_u() const {
369     return static_cast<uint32_t>(get_register(rt_reg()));
370   }
rd_reg()371   inline int32_t rd_reg() const { return instr_.RdValue(); }
fr_reg()372   inline int32_t fr_reg() const { return instr_.FrValue(); }
fs_reg()373   inline int32_t fs_reg() const { return instr_.FsValue(); }
ft_reg()374   inline int32_t ft_reg() const { return instr_.FtValue(); }
fd_reg()375   inline int32_t fd_reg() const { return instr_.FdValue(); }
sa()376   inline int32_t sa() const { return instr_.SaValue(); }
lsa_sa()377   inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
378 
SetResult(int32_t rd_reg,int32_t alu_out)379   inline void SetResult(int32_t rd_reg, int32_t alu_out) {
380     set_register(rd_reg, alu_out);
381     TraceRegWr(alu_out);
382   }
383 
384   void DecodeTypeImmediate();
385   void DecodeTypeJump();
386 
387   // Used for breakpoints and traps.
388   void SoftwareInterrupt();
389 
390   // Compact branch guard.
CheckForbiddenSlot(int32_t current_pc)391   void CheckForbiddenSlot(int32_t current_pc) {
392     Instruction* instr_after_compact_branch =
393         reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
394     if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
395       V8_Fatal(__FILE__, __LINE__,
396                "Error: Unexpected instruction 0x%08x immediately after a "
397                "compact branch instruction.",
398                *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
399     }
400   }
401 
402   // Stop helper functions.
403   bool IsWatchpoint(uint32_t code);
404   void PrintWatchpoint(uint32_t code);
405   void HandleStop(uint32_t code, Instruction* instr);
406   bool IsStopInstruction(Instruction* instr);
407   bool IsEnabledStop(uint32_t code);
408   void EnableStop(uint32_t code);
409   void DisableStop(uint32_t code);
410   void IncreaseStopCounter(uint32_t code);
411   void PrintStopInfo(uint32_t code);
412 
413 
414   // Executes one instruction.
415   void InstructionDecode(Instruction* instr);
416   // Execute one instruction placed in a branch delay slot.
BranchDelayInstructionDecode(Instruction * instr)417   void BranchDelayInstructionDecode(Instruction* instr) {
418     if (instr->InstructionBits() == nopInstr) {
419       // Short-cut generic nop instructions. They are always valid and they
420       // never change the simulator state.
421       return;
422     }
423 
424     if (instr->IsForbiddenInBranchDelay()) {
425       V8_Fatal(__FILE__, __LINE__,
426                "Eror:Unexpected %i opcode in a branch delay slot.",
427                instr->OpcodeValue());
428     }
429     InstructionDecode(instr);
430     SNPrintF(trace_buf_, " ");
431   }
432 
433   // ICache.
434   static void CheckICache(base::CustomMatcherHashMap* i_cache,
435                           Instruction* instr);
436   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
437                            int size);
438   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
439                                  void* page);
440 
441   enum Exception {
442     none,
443     kIntegerOverflow,
444     kIntegerUnderflow,
445     kDivideByZero,
446     kNumExceptions
447   };
448 
449   // Exceptions.
450   void SignalException(Exception e);
451 
452   // Runtime call support.
453   static void* RedirectExternalReference(Isolate* isolate,
454                                          void* external_function,
455                                          ExternalReference::Type type);
456 
457   // Handle arguments and return value for runtime FP functions.
458   void GetFpArgs(double* x, double* y, int32_t* z);
459   void SetFpResult(const double& result);
460 
461   void CallInternal(byte* entry);
462 
463   // Architecture state.
464   // Registers.
465   int32_t registers_[kNumSimuRegisters];
466   // Coprocessor Registers.
467   // Note: FP32 mode uses only the lower 32-bit part of each element,
468   // the upper 32-bit is unpredictable.
469   int64_t FPUregisters_[kNumFPURegisters];
470   // FPU control register.
471   uint32_t FCSR_;
472 
473   // Simulator support.
474   // Allocate 1MB for stack.
475   static const size_t stack_size_ = 1 * 1024*1024;
476   char* stack_;
477   bool pc_modified_;
478   uint64_t icount_;
479   int break_count_;
480 
481   // Debugger input.
482   char* last_debugger_input_;
483 
484   // Icache simulation.
485   base::CustomMatcherHashMap* i_cache_;
486 
487   v8::internal::Isolate* isolate_;
488 
489   // Registered breakpoints.
490   Instruction* break_pc_;
491   Instr break_instr_;
492 
493   // Stop is disabled if bit 31 is set.
494   static const uint32_t kStopDisabledBit = 1 << 31;
495 
496   // A stop is enabled, meaning the simulator will stop when meeting the
497   // instruction, if bit 31 of watched_stops_[code].count is unset.
498   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
499   // the breakpoint was hit or gone through.
500   struct StopCountAndDesc {
501     uint32_t count;
502     char* desc;
503   };
504   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
505 };
506 
507 
508 // When running with the simulator transition into simulated execution at this
509 // point.
510 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
511   reinterpret_cast<Object*>(Simulator::current(isolate)->Call(  \
512       FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
513 
514 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
515                                    p7, p8)                                     \
516   Simulator::current(isolate)                                                  \
517       ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
518 
519 
520 // The simulator has its own stack. Thus it has a different stack limit from
521 // the C-based native code.  The JS-based limit normally points near the end of
522 // the simulator stack.  When the C-based limit is exhausted we reflect that by
523 // lowering the JS-based limit as well, to make stack checks trigger.
524 class SimulatorStack : public v8::internal::AllStatic {
525  public:
JsLimitFromCLimit(Isolate * isolate,uintptr_t c_limit)526   static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
527                                             uintptr_t c_limit) {
528     return Simulator::current(isolate)->StackLimit(c_limit);
529   }
530 
RegisterCTryCatch(Isolate * isolate,uintptr_t try_catch_address)531   static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
532                                             uintptr_t try_catch_address) {
533     Simulator* sim = Simulator::current(isolate);
534     return sim->PushAddress(try_catch_address);
535   }
536 
UnregisterCTryCatch(Isolate * isolate)537   static inline void UnregisterCTryCatch(Isolate* isolate) {
538     Simulator::current(isolate)->PopAddress();
539   }
540 };
541 
542 }  // namespace internal
543 }  // namespace v8
544 
545 #endif  // !defined(USE_SIMULATOR)
546 #endif  // V8_MIPS_SIMULATOR_MIPS_H_
547