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