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