• Home
  • 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 // Declares a Simulator for MIPS instructions if we are not generating a native
6 // MIPS binary. This Simulator allows us to run and debug MIPS code generation
7 // on regular desktop machines.
8 // V8 calls into generated code via the GeneratedCode wrapper,
9 // which will start execution in the Simulator or forwards to the real entry
10 // on a MIPS HW platform.
11 
12 #ifndef V8_EXECUTION_MIPS_SIMULATOR_MIPS_H_
13 #define V8_EXECUTION_MIPS_SIMULATOR_MIPS_H_
14 
15 // globals.h defines USE_SIMULATOR.
16 #include "src/common/globals.h"
17 
18 template <typename T>
Compare(const T & a,const T & b)19 int Compare(const T& a, const T& b) {
20   if (a == b)
21     return 0;
22   else if (a < b)
23     return -1;
24   else
25     return 1;
26 }
27 
28 // Returns the negative absolute value of its argument.
29 template <typename T,
30           typename = typename std::enable_if<std::is_signed<T>::value>::type>
Nabs(T a)31 T Nabs(T a) {
32   return a < 0 ? a : -a;
33 }
34 
35 #if defined(USE_SIMULATOR)
36 // Running with a simulator.
37 
38 #include "src/base/hashmap.h"
39 #include "src/codegen/assembler.h"
40 #include "src/codegen/mips/constants-mips.h"
41 #include "src/execution/simulator-base.h"
42 #include "src/utils/allocation.h"
43 
44 namespace v8 {
45 namespace internal {
46 
47 // -----------------------------------------------------------------------------
48 // Utility functions
49 
50 class CachePage {
51  public:
52   static const int LINE_VALID = 0;
53   static const int LINE_INVALID = 1;
54 
55   static const int kPageShift = 12;
56   static const int kPageSize = 1 << kPageShift;
57   static const int kPageMask = kPageSize - 1;
58   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
59   static const int kLineLength = 1 << kLineShift;
60   static const int kLineMask = kLineLength - 1;
61 
CachePage()62   CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
63 
ValidityByte(int offset)64   char* ValidityByte(int offset) {
65     return &validity_map_[offset >> kLineShift];
66   }
67 
CachedData(int offset)68   char* CachedData(int offset) { return &data_[offset]; }
69 
70  private:
71   char data_[kPageSize];  // The cached data.
72   static const int kValidityMapSize = kPageSize >> kLineShift;
73   char validity_map_[kValidityMapSize];  // One byte per line.
74 };
75 
76 class SimInstructionBase : public InstructionBase {
77  public:
InstructionType()78   Type InstructionType() const { return type_; }
instr()79   inline Instruction* instr() const { return instr_; }
operand()80   inline int32_t operand() const { return operand_; }
81 
82  protected:
SimInstructionBase()83   SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
SimInstructionBase(Instruction * instr)84   explicit SimInstructionBase(Instruction* instr) {}
85 
86   int32_t operand_;
87   Instruction* instr_;
88   Type type_;
89 
90  private:
91   DISALLOW_ASSIGN(SimInstructionBase);
92 };
93 
94 class SimInstruction : public InstructionGetters<SimInstructionBase> {
95  public:
SimInstruction()96   SimInstruction() {}
97 
SimInstruction(Instruction * instr)98   explicit SimInstruction(Instruction* instr) { *this = instr; }
99 
100   SimInstruction& operator=(Instruction* instr) {
101     operand_ = *reinterpret_cast<const int32_t*>(instr);
102     instr_ = instr;
103     type_ = InstructionBase::InstructionType();
104     DCHECK(reinterpret_cast<void*>(&operand_) == this);
105     return *this;
106   }
107 };
108 
109 class Simulator : public SimulatorBase {
110  public:
111   friend class MipsDebugger;
112 
113   // Registers are declared in order. See SMRL chapter 2.
114   enum Register {
115     no_reg = -1,
116     zero_reg = 0,
117     at,
118     v0,
119     v1,
120     a0,
121     a1,
122     a2,
123     a3,
124     t0,
125     t1,
126     t2,
127     t3,
128     t4,
129     t5,
130     t6,
131     t7,
132     s0,
133     s1,
134     s2,
135     s3,
136     s4,
137     s5,
138     s6,
139     s7,
140     t8,
141     t9,
142     k0,
143     k1,
144     gp,
145     sp,
146     s8,
147     ra,
148     // LO, HI, and pc.
149     LO,
150     HI,
151     pc,  // pc must be the last register.
152     kNumSimuRegisters,
153     // aliases
154     fp = s8
155   };
156 
157   // Coprocessor registers.
158   // Generated code will always use doubles. So we will only use even registers.
159   enum FPURegister {
160     f0,
161     f1,
162     f2,
163     f3,
164     f4,
165     f5,
166     f6,
167     f7,
168     f8,
169     f9,
170     f10,
171     f11,
172     f12,
173     f13,
174     f14,
175     f15,  // f12 and f14 are arguments FPURegisters.
176     f16,
177     f17,
178     f18,
179     f19,
180     f20,
181     f21,
182     f22,
183     f23,
184     f24,
185     f25,
186     f26,
187     f27,
188     f28,
189     f29,
190     f30,
191     f31,
192     kNumFPURegisters
193   };
194 
195   // MSA registers
196   enum MSARegister {
197     w0,
198     w1,
199     w2,
200     w3,
201     w4,
202     w5,
203     w6,
204     w7,
205     w8,
206     w9,
207     w10,
208     w11,
209     w12,
210     w13,
211     w14,
212     w15,
213     w16,
214     w17,
215     w18,
216     w19,
217     w20,
218     w21,
219     w22,
220     w23,
221     w24,
222     w25,
223     w26,
224     w27,
225     w28,
226     w29,
227     w30,
228     w31,
229     kNumMSARegisters
230   };
231 
232   explicit Simulator(Isolate* isolate);
233   ~Simulator();
234 
235   // The currently executing Simulator instance. Potentially there can be one
236   // for each native thread.
237   V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate);
238 
239   // Accessors for register state. Reading the pc value adheres to the MIPS
240   // architecture specification and is off by a 8 from the currently executing
241   // instruction.
242   void set_register(int reg, int32_t value);
243   void set_dw_register(int dreg, const int* dbl);
244   int32_t get_register(int reg) const;
245   double get_double_from_register_pair(int reg);
246   // Same for FPURegisters.
247   void set_fpu_register(int fpureg, int64_t value);
248   void set_fpu_register_word(int fpureg, int32_t value);
249   void set_fpu_register_hi_word(int fpureg, int32_t value);
250   void set_fpu_register_float(int fpureg, float value);
251   void set_fpu_register_double(int fpureg, double value);
252   void set_fpu_register_invalid_result64(float original, float rounded);
253   void set_fpu_register_invalid_result(float original, float rounded);
254   void set_fpu_register_word_invalid_result(float original, float rounded);
255   void set_fpu_register_invalid_result64(double original, double rounded);
256   void set_fpu_register_invalid_result(double original, double rounded);
257   void set_fpu_register_word_invalid_result(double original, double rounded);
258   int64_t get_fpu_register(int fpureg) const;
259   int32_t get_fpu_register_word(int fpureg) const;
260   int32_t get_fpu_register_signed_word(int fpureg) const;
261   int32_t get_fpu_register_hi_word(int fpureg) const;
262   float get_fpu_register_float(int fpureg) const;
263   double get_fpu_register_double(int fpureg) const;
264   template <typename T>
265   void get_msa_register(int wreg, T* value);
266   template <typename T>
267   void set_msa_register(int wreg, const T* value);
268   void set_fcsr_bit(uint32_t cc, bool value);
269   bool test_fcsr_bit(uint32_t cc);
270   void set_fcsr_rounding_mode(FPURoundingMode mode);
271   void set_msacsr_rounding_mode(FPURoundingMode mode);
272   unsigned int get_fcsr_rounding_mode();
273   unsigned int get_msacsr_rounding_mode();
274   bool set_fcsr_round_error(double original, double rounded);
275   bool set_fcsr_round_error(float original, float rounded);
276   bool set_fcsr_round64_error(double original, double rounded);
277   bool set_fcsr_round64_error(float original, float rounded);
278   void round_according_to_fcsr(double toRound, double* rounded,
279                                int32_t* rounded_int, double fs);
280   void round_according_to_fcsr(float toRound, float* rounded,
281                                int32_t* rounded_int, float fs);
282   template <typename Tfp, typename Tint>
283   void round_according_to_msacsr(Tfp toRound, Tfp* rounded, Tint* rounded_int);
284   void round64_according_to_fcsr(double toRound, double* rounded,
285                                  int64_t* rounded_int, double fs);
286   void round64_according_to_fcsr(float toRound, float* rounded,
287                                  int64_t* rounded_int, float fs);
288   // Special case of set_register and get_register to access the raw PC value.
289   void set_pc(int32_t value);
290   int32_t get_pc() const;
291 
get_sp()292   Address get_sp() const { return static_cast<Address>(get_register(sp)); }
293 
294   // Accessor to the internal simulator stack area.
295   uintptr_t StackLimit(uintptr_t c_limit) const;
296 
297   // Executes MIPS instructions until the PC reaches end_sim_pc.
298   void Execute();
299 
300   template <typename Return, typename... Args>
Call(Address entry,Args...args)301   Return Call(Address entry, Args... args) {
302     return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
303   }
304 
305   // Alternative: call a 2-argument double function.
306   double CallFP(Address entry, double d0, double d1);
307 
308   // Push an address onto the JS stack.
309   uintptr_t PushAddress(uintptr_t address);
310 
311   // Pop an address from the JS stack.
312   uintptr_t PopAddress();
313 
314   // Debugger input.
315   void set_last_debugger_input(char* input);
last_debugger_input()316   char* last_debugger_input() { return last_debugger_input_; }
317 
318   // Redirection support.
319   static void SetRedirectInstruction(Instruction* instruction);
320 
321   // ICache checking.
322   static bool ICacheMatch(void* one, void* two);
323   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
324                           size_t size);
325 
326   // Returns true if pc register contains one of the 'special_values' defined
327   // below (bad_ra, end_sim_pc).
328   bool has_bad_pc() const;
329 
330  private:
331   enum special_values {
332     // Known bad pc value to ensure that the simulator does not execute
333     // without being properly setup.
334     bad_ra = -1,
335     // A pc value used to signal the simulator to stop execution.  Generally
336     // the ra is set to this value on transition from native C code to
337     // simulated execution, so that the simulator can "return" to the native
338     // C code.
339     end_sim_pc = -2,
340     // Unpredictable value.
341     Unpredictable = 0xbadbeaf
342   };
343 
344   V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
345                                       const intptr_t* arguments);
346 
347   // Unsupported instructions use Format to print an error and stop execution.
348   void Format(Instruction* instr, const char* format);
349 
350   // Helpers for data value tracing.
351   enum TraceType { BYTE, HALF, WORD, DWORD, FLOAT, DOUBLE, FLOAT_DOUBLE };
352 
353   // MSA Data Format
354   enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
355   union msa_reg_t {
356     int8_t b[kMSALanesByte];
357     uint8_t ub[kMSALanesByte];
358     int16_t h[kMSALanesHalf];
359     uint16_t uh[kMSALanesHalf];
360     int32_t w[kMSALanesWord];
361     uint32_t uw[kMSALanesWord];
362     int64_t d[kMSALanesDword];
363     uint64_t ud[kMSALanesDword];
364   };
365 
366   // Read and write memory.
367   inline uint32_t ReadBU(int32_t addr);
368   inline int32_t ReadB(int32_t addr);
369   inline void WriteB(int32_t addr, uint8_t value);
370   inline void WriteB(int32_t addr, int8_t value);
371 
372   inline uint16_t ReadHU(int32_t addr, Instruction* instr);
373   inline int16_t ReadH(int32_t addr, Instruction* instr);
374   // Note: Overloaded on the sign of the value.
375   inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
376   inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
377 
378   inline int ReadW(int32_t addr, Instruction* instr, TraceType t = WORD);
379   inline void WriteW(int32_t addr, int value, Instruction* instr);
380   void WriteConditionalW(int32_t addr, int32_t value, Instruction* instr,
381                          int32_t rt_reg);
382 
383   inline double ReadD(int32_t addr, Instruction* instr);
384   inline void WriteD(int32_t addr, double value, Instruction* instr);
385 
386   template <typename T>
387   T ReadMem(int32_t addr, Instruction* instr);
388 
389   template <typename T>
390   void WriteMem(int32_t addr, T value, Instruction* instr);
391 
392   void TraceRegWr(int32_t value, TraceType t = WORD);
393   void TraceRegWr(int64_t value, TraceType t = DWORD);
394   template <typename T>
395   void TraceMSARegWr(T* value, TraceType t);
396   template <typename T>
397   void TraceMSARegWr(T* value);
398   void TraceMemWr(int32_t addr, int32_t value, TraceType t = WORD);
399   void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD);
400   void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD);
401   void TraceMemRd(int32_t addr, int64_t value, TraceType t = DWORD);
402   template <typename T>
403   void TraceMemRd(int32_t addr, T value);
404   template <typename T>
405   void TraceMemWr(int32_t addr, T value);
406   EmbeddedVector<char, 128> trace_buf_;
407 
408   // Operations depending on endianness.
409   // Get Double Higher / Lower word.
410   inline int32_t GetDoubleHIW(double* addr);
411   inline int32_t GetDoubleLOW(double* addr);
412   // Set Double Higher / Lower word.
413   inline int32_t SetDoubleHIW(double* addr);
414   inline int32_t SetDoubleLOW(double* addr);
415 
416   SimInstruction instr_;
417 
418   // Executing is handled based on the instruction type.
419   void DecodeTypeRegister();
420 
421   // Functions called from DecodeTypeRegister.
422   void DecodeTypeRegisterCOP1();
423 
424   void DecodeTypeRegisterCOP1X();
425 
426   void DecodeTypeRegisterSPECIAL();
427 
428   void DecodeTypeRegisterSPECIAL2();
429 
430   void DecodeTypeRegisterSPECIAL3();
431 
432   // Called from DecodeTypeRegisterCOP1.
433   void DecodeTypeRegisterSRsType();
434 
435   void DecodeTypeRegisterDRsType();
436 
437   void DecodeTypeRegisterWRsType();
438 
439   void DecodeTypeRegisterLRsType();
440 
441   int DecodeMsaDataFormat();
442   void DecodeTypeMsaI8();
443   void DecodeTypeMsaI5();
444   void DecodeTypeMsaI10();
445   void DecodeTypeMsaELM();
446   void DecodeTypeMsaBIT();
447   void DecodeTypeMsaMI10();
448   void DecodeTypeMsa3R();
449   void DecodeTypeMsa3RF();
450   void DecodeTypeMsaVec();
451   void DecodeTypeMsa2R();
452   void DecodeTypeMsa2RF();
453   template <typename T>
454   T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
455   template <typename T>
456   T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
457   template <typename T>
458   T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt);
459 
rs_reg()460   inline int32_t rs_reg() const { return instr_.RsValue(); }
rs()461   inline int32_t rs() const { return get_register(rs_reg()); }
rs_u()462   inline uint32_t rs_u() const {
463     return static_cast<uint32_t>(get_register(rs_reg()));
464   }
rt_reg()465   inline int32_t rt_reg() const { return instr_.RtValue(); }
rt()466   inline int32_t rt() const { return get_register(rt_reg()); }
rt_u()467   inline uint32_t rt_u() const {
468     return static_cast<uint32_t>(get_register(rt_reg()));
469   }
rd_reg()470   inline int32_t rd_reg() const { return instr_.RdValue(); }
fr_reg()471   inline int32_t fr_reg() const { return instr_.FrValue(); }
fs_reg()472   inline int32_t fs_reg() const { return instr_.FsValue(); }
ft_reg()473   inline int32_t ft_reg() const { return instr_.FtValue(); }
fd_reg()474   inline int32_t fd_reg() const { return instr_.FdValue(); }
sa()475   inline int32_t sa() const { return instr_.SaValue(); }
lsa_sa()476   inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
ws_reg()477   inline int32_t ws_reg() const { return instr_.WsValue(); }
wt_reg()478   inline int32_t wt_reg() const { return instr_.WtValue(); }
wd_reg()479   inline int32_t wd_reg() const { return instr_.WdValue(); }
480 
SetResult(int32_t rd_reg,int32_t alu_out)481   inline void SetResult(int32_t rd_reg, int32_t alu_out) {
482     set_register(rd_reg, alu_out);
483     TraceRegWr(alu_out);
484   }
485 
SetFPUWordResult(int32_t fd_reg,int32_t alu_out)486   inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) {
487     set_fpu_register_word(fd_reg, alu_out);
488     TraceRegWr(get_fpu_register_word(fd_reg));
489   }
490 
SetFPUResult(int32_t fd_reg,int64_t alu_out)491   inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) {
492     set_fpu_register(fd_reg, alu_out);
493     TraceRegWr(get_fpu_register(fd_reg));
494   }
495 
SetFPUFloatResult(int32_t fd_reg,float alu_out)496   inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) {
497     set_fpu_register_float(fd_reg, alu_out);
498     TraceRegWr(get_fpu_register_word(fd_reg), FLOAT);
499   }
500 
SetFPUDoubleResult(int32_t fd_reg,double alu_out)501   inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) {
502     set_fpu_register_double(fd_reg, alu_out);
503     TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
504   }
505 
506   void DecodeTypeImmediate();
507   void DecodeTypeJump();
508 
509   // Used for breakpoints and traps.
510   void SoftwareInterrupt();
511 
512   // Compact branch guard.
CheckForbiddenSlot(int32_t current_pc)513   void CheckForbiddenSlot(int32_t current_pc) {
514     Instruction* instr_after_compact_branch =
515         reinterpret_cast<Instruction*>(current_pc + kInstrSize);
516     if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
517       FATAL(
518           "Error: Unexpected instruction 0x%08x immediately after a "
519           "compact branch instruction.",
520           *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
521     }
522   }
523 
524   // Stop helper functions.
525   bool IsWatchpoint(uint32_t code);
526   void PrintWatchpoint(uint32_t code);
527   void HandleStop(uint32_t code, Instruction* instr);
528   bool IsStopInstruction(Instruction* instr);
529   bool IsEnabledStop(uint32_t code);
530   void EnableStop(uint32_t code);
531   void DisableStop(uint32_t code);
532   void IncreaseStopCounter(uint32_t code);
533   void PrintStopInfo(uint32_t code);
534 
535   // Executes one instruction.
536   void InstructionDecode(Instruction* instr);
537   // Execute one instruction placed in a branch delay slot.
BranchDelayInstructionDecode(Instruction * instr)538   void BranchDelayInstructionDecode(Instruction* instr) {
539     if (instr->InstructionBits() == nopInstr) {
540       // Short-cut generic nop instructions. They are always valid and they
541       // never change the simulator state.
542       return;
543     }
544 
545     if (instr->IsForbiddenInBranchDelay()) {
546       FATAL("Eror:Unexpected %i opcode in a branch delay slot.",
547             instr->OpcodeValue());
548     }
549     InstructionDecode(instr);
550     SNPrintF(trace_buf_, " ");
551   }
552 
553   // ICache.
554   static void CheckICache(base::CustomMatcherHashMap* i_cache,
555                           Instruction* instr);
556   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
557                            int size);
558   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
559                                  void* page);
560 
561   enum Exception {
562     none,
563     kIntegerOverflow,
564     kIntegerUnderflow,
565     kDivideByZero,
566     kNumExceptions
567   };
568 
569   // Exceptions.
570   void SignalException(Exception e);
571 
572   // Handle arguments and return value for runtime FP functions.
573   void GetFpArgs(double* x, double* y, int32_t* z);
574   void SetFpResult(const double& result);
575 
576   void CallInternal(Address entry);
577 
578   // Architecture state.
579   // Registers.
580   int32_t registers_[kNumSimuRegisters];
581   // Coprocessor Registers.
582   // Note: FP32 mode uses only the lower 32-bit part of each element,
583   // the upper 32-bit is unpredictable.
584   // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
585   // order to support MSA registers
586   int64_t FPUregisters_[kNumFPURegisters * 2];
587   // FPU control register.
588   uint32_t FCSR_;
589   // MSA control register.
590   uint32_t MSACSR_;
591 
592   // Simulator support.
593   size_t stack_size_;
594   char* stack_;
595   bool pc_modified_;
596   uint64_t icount_;
597   int break_count_;
598 
599   // Debugger input.
600   char* last_debugger_input_;
601 
602   v8::internal::Isolate* isolate_;
603 
604   // Registered breakpoints.
605   Instruction* break_pc_;
606   Instr break_instr_;
607 
608   // Stop is disabled if bit 31 is set.
609   static const uint32_t kStopDisabledBit = 1 << 31;
610 
611   // A stop is enabled, meaning the simulator will stop when meeting the
612   // instruction, if bit 31 of watched_stops_[code].count is unset.
613   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
614   // the breakpoint was hit or gone through.
615   struct StopCountAndDesc {
616     uint32_t count;
617     char* desc;
618   };
619   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
620 
621   // Synchronization primitives.
622   enum class MonitorAccess {
623     Open,
624     RMW,
625   };
626 
627   enum class TransactionSize {
628     None = 0,
629     Word = 4,
630   };
631 
632   // The least-significant bits of the address are ignored. The number of bits
633   // is implementation-defined, between 3 and minimum page size.
634   static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 3) - 1);
635 
636   class LocalMonitor {
637    public:
638     LocalMonitor();
639 
640     // These functions manage the state machine for the local monitor, but do
641     // not actually perform loads and stores. NotifyStoreConditional only
642     // returns true if the store conditional is allowed; the global monitor will
643     // still have to be checked to see whether the memory should be updated.
644     void NotifyLoad();
645     void NotifyLoadLinked(uintptr_t addr, TransactionSize size);
646     void NotifyStore();
647     bool NotifyStoreConditional(uintptr_t addr, TransactionSize size);
648 
649    private:
650     void Clear();
651 
652     MonitorAccess access_state_;
653     uintptr_t tagged_addr_;
654     TransactionSize size_;
655   };
656 
657   class GlobalMonitor {
658    public:
659     class LinkedAddress {
660      public:
661       LinkedAddress();
662 
663      private:
664       friend class GlobalMonitor;
665       // These functions manage the state machine for the global monitor, but do
666       // not actually perform loads and stores.
667       void Clear_Locked();
668       void NotifyLoadLinked_Locked(uintptr_t addr);
669       void NotifyStore_Locked();
670       bool NotifyStoreConditional_Locked(uintptr_t addr,
671                                          bool is_requesting_thread);
672 
673       MonitorAccess access_state_;
674       uintptr_t tagged_addr_;
675       LinkedAddress* next_;
676       LinkedAddress* prev_;
677       // A scd can fail due to background cache evictions. Rather than
678       // simulating this, we'll just occasionally introduce cases where an
679       // store conditional fails. This will happen once after every
680       // kMaxFailureCounter exclusive stores.
681       static const int kMaxFailureCounter = 5;
682       int failure_counter_;
683     };
684 
685     // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
686     base::Mutex mutex;
687 
688     void NotifyLoadLinked_Locked(uintptr_t addr, LinkedAddress* linked_address);
689     void NotifyStore_Locked(LinkedAddress* linked_address);
690     bool NotifyStoreConditional_Locked(uintptr_t addr,
691                                        LinkedAddress* linked_address);
692 
693     // Called when the simulator is destroyed.
694     void RemoveLinkedAddress(LinkedAddress* linked_address);
695 
696     static GlobalMonitor* Get();
697 
698    private:
699     // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
700     GlobalMonitor() = default;
701     friend class base::LeakyObject<GlobalMonitor>;
702 
703     bool IsProcessorInLinkedList_Locked(LinkedAddress* linked_address) const;
704     void PrependProcessor_Locked(LinkedAddress* linked_address);
705 
706     LinkedAddress* head_ = nullptr;
707   };
708 
709   LocalMonitor local_monitor_;
710   GlobalMonitor::LinkedAddress global_monitor_thread_;
711 };
712 
713 }  // namespace internal
714 }  // namespace v8
715 
716 #endif  // defined(USE_SIMULATOR)
717 #endif  // V8_EXECUTION_MIPS_SIMULATOR_MIPS_H_
718