• 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_MIPS64_SIMULATOR_MIPS64_H_
13 #define V8_EXECUTION_MIPS64_SIMULATOR_MIPS64_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/mips64/constants-mips64.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     a4,
126     a5,
127     a6,
128     a7,
129     t0,
130     t1,
131     t2,
132     t3,
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, int64_t value);
244   void set_register_word(int reg, int32_t value);
245   void set_dw_register(int dreg, const int* dbl);
246   V8_EXPORT_PRIVATE int64_t get_register(int reg) const;
247   double get_double_from_register_pair(int reg);
248   // Same for FPURegisters.
249   void set_fpu_register(int fpureg, int64_t value);
250   void set_fpu_register_word(int fpureg, int32_t value);
251   void set_fpu_register_hi_word(int fpureg, int32_t value);
252   void set_fpu_register_float(int fpureg, float value);
253   void set_fpu_register_double(int fpureg, double value);
254   void set_fpu_register_invalid_result64(float original, float rounded);
255   void set_fpu_register_invalid_result(float original, float rounded);
256   void set_fpu_register_word_invalid_result(float original, float rounded);
257   void set_fpu_register_invalid_result64(double original, double rounded);
258   void set_fpu_register_invalid_result(double original, double rounded);
259   void set_fpu_register_word_invalid_result(double original, double rounded);
260   int64_t get_fpu_register(int fpureg) const;
261   int32_t get_fpu_register_word(int fpureg) const;
262   int32_t get_fpu_register_signed_word(int fpureg) const;
263   int32_t get_fpu_register_hi_word(int fpureg) const;
264   float get_fpu_register_float(int fpureg) const;
265   double get_fpu_register_double(int fpureg) const;
266   template <typename T>
267   void get_msa_register(int wreg, T* value);
268   template <typename T>
269   void set_msa_register(int wreg, const T* value);
270   void set_fcsr_bit(uint32_t cc, bool value);
271   bool test_fcsr_bit(uint32_t cc);
272   bool set_fcsr_round_error(double original, double rounded);
273   bool set_fcsr_round64_error(double original, double rounded);
274   bool set_fcsr_round_error(float original, float rounded);
275   bool set_fcsr_round64_error(float original, float rounded);
276   void round_according_to_fcsr(double toRound, double* rounded,
277                                int32_t* rounded_int, double fs);
278   void round64_according_to_fcsr(double toRound, double* rounded,
279                                  int64_t* rounded_int, double fs);
280   void round_according_to_fcsr(float toRound, float* rounded,
281                                int32_t* rounded_int, float fs);
282   void round64_according_to_fcsr(float toRound, float* rounded,
283                                  int64_t* rounded_int, float fs);
284   template <typename T_fp, typename T_int>
285   void round_according_to_msacsr(T_fp toRound, T_fp* rounded,
286                                  T_int* rounded_int);
287   void clear_fcsr_cause();
288   void set_fcsr_rounding_mode(FPURoundingMode mode);
289   void set_msacsr_rounding_mode(FPURoundingMode mode);
290   unsigned int get_fcsr_rounding_mode();
291   unsigned int get_msacsr_rounding_mode();
292   // Special case of set_register and get_register to access the raw PC value.
293   void set_pc(int64_t value);
294   V8_EXPORT_PRIVATE int64_t get_pc() const;
295 
get_sp()296   Address get_sp() const { return static_cast<Address>(get_register(sp)); }
297 
298   // Accessor to the internal simulator stack area.
299   uintptr_t StackLimit(uintptr_t c_limit) const;
300 
301   // Executes MIPS instructions until the PC reaches end_sim_pc.
302   void Execute();
303 
304   template <typename Return, typename... Args>
Call(Address entry,Args...args)305   Return Call(Address entry, Args... args) {
306     return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
307   }
308 
309   // Alternative: call a 2-argument double function.
310   double CallFP(Address entry, double d0, double d1);
311 
312   // Push an address onto the JS stack.
313   uintptr_t PushAddress(uintptr_t address);
314 
315   // Pop an address from the JS stack.
316   uintptr_t PopAddress();
317 
318   // Debugger input.
319   void set_last_debugger_input(char* input);
last_debugger_input()320   char* last_debugger_input() { return last_debugger_input_; }
321 
322   // Redirection support.
323   static void SetRedirectInstruction(Instruction* instruction);
324 
325   // ICache checking.
326   static bool ICacheMatch(void* one, void* two);
327   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
328                           size_t size);
329 
330   // Returns true if pc register contains one of the 'special_values' defined
331   // below (bad_ra, end_sim_pc).
332   bool has_bad_pc() const;
333 
334  private:
335   enum special_values {
336     // Known bad pc value to ensure that the simulator does not execute
337     // without being properly setup.
338     bad_ra = -1,
339     // A pc value used to signal the simulator to stop execution.  Generally
340     // the ra is set to this value on transition from native C code to
341     // simulated execution, so that the simulator can "return" to the native
342     // C code.
343     end_sim_pc = -2,
344     // Unpredictable value.
345     Unpredictable = 0xbadbeaf
346   };
347 
348   V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
349                                       const intptr_t* arguments);
350 
351   // Unsupported instructions use Format to print an error and stop execution.
352   void Format(Instruction* instr, const char* format);
353 
354   // Helpers for data value tracing.
355   enum TraceType {
356     BYTE,
357     HALF,
358     WORD,
359     DWORD,
360     FLOAT,
361     DOUBLE,
362     FLOAT_DOUBLE,
363     WORD_DWORD
364   };
365 
366   // MSA Data Format
367   enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
368   union msa_reg_t {
369     int8_t b[kMSALanesByte];
370     uint8_t ub[kMSALanesByte];
371     int16_t h[kMSALanesHalf];
372     uint16_t uh[kMSALanesHalf];
373     int32_t w[kMSALanesWord];
374     uint32_t uw[kMSALanesWord];
375     int64_t d[kMSALanesDword];
376     uint64_t ud[kMSALanesDword];
377   };
378 
379   // Read and write memory.
380   inline uint32_t ReadBU(int64_t addr);
381   inline int32_t ReadB(int64_t addr);
382   inline void WriteB(int64_t addr, uint8_t value);
383   inline void WriteB(int64_t addr, int8_t value);
384 
385   inline uint16_t ReadHU(int64_t addr, Instruction* instr);
386   inline int16_t ReadH(int64_t addr, Instruction* instr);
387   // Note: Overloaded on the sign of the value.
388   inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
389   inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
390 
391   inline uint32_t ReadWU(int64_t addr, Instruction* instr);
392   inline int32_t ReadW(int64_t addr, Instruction* instr, TraceType t = WORD);
393   inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
394   void WriteConditionalW(int64_t addr, int32_t value, Instruction* instr,
395                          int32_t rt_reg);
396   inline int64_t Read2W(int64_t addr, Instruction* instr);
397   inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
398   inline void WriteConditional2W(int64_t addr, int64_t value,
399                                  Instruction* instr, int32_t rt_reg);
400 
401   inline double ReadD(int64_t addr, Instruction* instr);
402   inline void WriteD(int64_t addr, double value, Instruction* instr);
403 
404   template <typename T>
405   T ReadMem(int64_t addr, Instruction* instr);
406   template <typename T>
407   void WriteMem(int64_t addr, T value, Instruction* instr);
408 
409   // Helper for debugging memory access.
410   inline void DieOrDebug();
411 
412   void TraceRegWr(int64_t value, TraceType t = DWORD);
413   template <typename T>
414   void TraceMSARegWr(T* value, TraceType t);
415   template <typename T>
416   void TraceMSARegWr(T* value);
417   void TraceMemWr(int64_t addr, int64_t value, TraceType t);
418   void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD);
419   template <typename T>
420   void TraceMemRd(int64_t addr, T value);
421   template <typename T>
422   void TraceMemWr(int64_t addr, T value);
423 
424   // Operations depending on endianness.
425   // Get Double Higher / Lower word.
426   inline int32_t GetDoubleHIW(double* addr);
427   inline int32_t GetDoubleLOW(double* addr);
428   // Set Double Higher / Lower word.
429   inline int32_t SetDoubleHIW(double* addr);
430   inline int32_t SetDoubleLOW(double* addr);
431 
432   SimInstruction instr_;
433 
434   // functions called from DecodeTypeRegister.
435   void DecodeTypeRegisterCOP1();
436 
437   void DecodeTypeRegisterCOP1X();
438 
439   void DecodeTypeRegisterSPECIAL();
440 
441   void DecodeTypeRegisterSPECIAL2();
442 
443   void DecodeTypeRegisterSPECIAL3();
444 
445   void DecodeTypeRegisterSRsType();
446 
447   void DecodeTypeRegisterDRsType();
448 
449   void DecodeTypeRegisterWRsType();
450 
451   void DecodeTypeRegisterLRsType();
452 
453   int DecodeMsaDataFormat();
454   void DecodeTypeMsaI8();
455   void DecodeTypeMsaI5();
456   void DecodeTypeMsaI10();
457   void DecodeTypeMsaELM();
458   void DecodeTypeMsaBIT();
459   void DecodeTypeMsaMI10();
460   void DecodeTypeMsa3R();
461   void DecodeTypeMsa3RF();
462   void DecodeTypeMsaVec();
463   void DecodeTypeMsa2R();
464   void DecodeTypeMsa2RF();
465   template <typename T>
466   T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
467   template <typename T>
468   T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
469   template <typename T>
470   T Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt);
471 
472   // Executing is handled based on the instruction type.
473   void DecodeTypeRegister();
474 
rs_reg()475   inline int32_t rs_reg() const { return instr_.RsValue(); }
rs()476   inline int64_t rs() const { return get_register(rs_reg()); }
rs_u()477   inline uint64_t rs_u() const {
478     return static_cast<uint64_t>(get_register(rs_reg()));
479   }
rt_reg()480   inline int32_t rt_reg() const { return instr_.RtValue(); }
rt()481   inline int64_t rt() const { return get_register(rt_reg()); }
rt_u()482   inline uint64_t rt_u() const {
483     return static_cast<uint64_t>(get_register(rt_reg()));
484   }
rd_reg()485   inline int32_t rd_reg() const { return instr_.RdValue(); }
fr_reg()486   inline int32_t fr_reg() const { return instr_.FrValue(); }
fs_reg()487   inline int32_t fs_reg() const { return instr_.FsValue(); }
ft_reg()488   inline int32_t ft_reg() const { return instr_.FtValue(); }
fd_reg()489   inline int32_t fd_reg() const { return instr_.FdValue(); }
sa()490   inline int32_t sa() const { return instr_.SaValue(); }
lsa_sa()491   inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
ws_reg()492   inline int32_t ws_reg() const { return instr_.WsValue(); }
wt_reg()493   inline int32_t wt_reg() const { return instr_.WtValue(); }
wd_reg()494   inline int32_t wd_reg() const { return instr_.WdValue(); }
495 
SetResult(const int32_t rd_reg,const int64_t alu_out)496   inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
497     set_register(rd_reg, alu_out);
498     TraceRegWr(alu_out);
499   }
500 
SetFPUWordResult(int32_t fd_reg,int32_t alu_out)501   inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) {
502     set_fpu_register_word(fd_reg, alu_out);
503     TraceRegWr(get_fpu_register(fd_reg), WORD);
504   }
505 
SetFPUWordResult2(int32_t fd_reg,int32_t alu_out)506   inline void SetFPUWordResult2(int32_t fd_reg, int32_t alu_out) {
507     set_fpu_register_word(fd_reg, alu_out);
508     TraceRegWr(get_fpu_register(fd_reg));
509   }
510 
SetFPUResult(int32_t fd_reg,int64_t alu_out)511   inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) {
512     set_fpu_register(fd_reg, alu_out);
513     TraceRegWr(get_fpu_register(fd_reg));
514   }
515 
SetFPUResult2(int32_t fd_reg,int64_t alu_out)516   inline void SetFPUResult2(int32_t fd_reg, int64_t alu_out) {
517     set_fpu_register(fd_reg, alu_out);
518     TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
519   }
520 
SetFPUFloatResult(int32_t fd_reg,float alu_out)521   inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) {
522     set_fpu_register_float(fd_reg, alu_out);
523     TraceRegWr(get_fpu_register(fd_reg), FLOAT);
524   }
525 
SetFPUDoubleResult(int32_t fd_reg,double alu_out)526   inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) {
527     set_fpu_register_double(fd_reg, alu_out);
528     TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
529   }
530 
531   void DecodeTypeImmediate();
532   void DecodeTypeJump();
533 
534   // Used for breakpoints and traps.
535   void SoftwareInterrupt();
536 
537   // Compact branch guard.
CheckForbiddenSlot(int64_t current_pc)538   void CheckForbiddenSlot(int64_t current_pc) {
539     Instruction* instr_after_compact_branch =
540         reinterpret_cast<Instruction*>(current_pc + kInstrSize);
541     if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
542       FATAL(
543           "Error: Unexpected instruction 0x%08x immediately after a "
544           "compact branch instruction.",
545           *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
546     }
547   }
548 
549   // Stop helper functions.
550   bool IsWatchpoint(uint64_t code);
551   void PrintWatchpoint(uint64_t code);
552   void HandleStop(uint64_t code, Instruction* instr);
553   bool IsStopInstruction(Instruction* instr);
554   bool IsEnabledStop(uint64_t code);
555   void EnableStop(uint64_t code);
556   void DisableStop(uint64_t code);
557   void IncreaseStopCounter(uint64_t code);
558   void PrintStopInfo(uint64_t code);
559 
560   // Executes one instruction.
561   void InstructionDecode(Instruction* instr);
562   // Execute one instruction placed in a branch delay slot.
BranchDelayInstructionDecode(Instruction * instr)563   void BranchDelayInstructionDecode(Instruction* instr) {
564     if (instr->InstructionBits() == nopInstr) {
565       // Short-cut generic nop instructions. They are always valid and they
566       // never change the simulator state.
567       return;
568     }
569 
570     if (instr->IsForbiddenAfterBranch()) {
571       FATAL("Eror:Unexpected %i opcode in a branch delay slot.",
572             instr->OpcodeValue());
573     }
574     InstructionDecode(instr);
575     SNPrintF(trace_buf_, " ");
576   }
577 
578   // ICache.
579   static void CheckICache(base::CustomMatcherHashMap* i_cache,
580                           Instruction* instr);
581   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
582                            size_t size);
583   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
584                                  void* page);
585 
586   enum Exception {
587     none,
588     kIntegerOverflow,
589     kIntegerUnderflow,
590     kDivideByZero,
591     kNumExceptions
592   };
593 
594   // Exceptions.
595   void SignalException(Exception e);
596 
597   // Handle arguments and return value for runtime FP functions.
598   void GetFpArgs(double* x, double* y, int32_t* z);
599   void SetFpResult(const double& result);
600 
601   void CallInternal(Address entry);
602 
603   // Architecture state.
604   // Registers.
605   int64_t registers_[kNumSimuRegisters];
606   // Coprocessor Registers.
607   // Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
608   // order to support MSA registers
609   int64_t FPUregisters_[kNumFPURegisters * 2];
610   // FPU control register.
611   uint32_t FCSR_;
612   // MSA control register.
613   uint32_t MSACSR_;
614 
615   // Simulator support.
616   // Allocate 1MB for stack.
617   size_t stack_size_;
618   char* stack_;
619   bool pc_modified_;
620   int64_t icount_;
621   int break_count_;
622   base::EmbeddedVector<char, 128> trace_buf_;
623 
624   // Debugger input.
625   char* last_debugger_input_;
626 
627   v8::internal::Isolate* isolate_;
628 
629   // Registered breakpoints.
630   Instruction* break_pc_;
631   Instr break_instr_;
632 
633   // Stop is disabled if bit 31 is set.
634   static const uint32_t kStopDisabledBit = 1 << 31;
635 
636   // A stop is enabled, meaning the simulator will stop when meeting the
637   // instruction, if bit 31 of watched_stops_[code].count is unset.
638   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
639   // the breakpoint was hit or gone through.
640   struct StopCountAndDesc {
641     uint32_t count;
642     char* desc;
643   };
644   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
645 
646   // Synchronization primitives.
647   enum class MonitorAccess {
648     Open,
649     RMW,
650   };
651 
652   enum class TransactionSize {
653     None = 0,
654     Word = 4,
655     DoubleWord = 8,
656   };
657 
658   // The least-significant bits of the address are ignored. The number of bits
659   // is implementation-defined, between 3 and minimum page size.
660   static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 3) - 1);
661 
662   class LocalMonitor {
663    public:
664     LocalMonitor();
665 
666     // These functions manage the state machine for the local monitor, but do
667     // not actually perform loads and stores. NotifyStoreConditional only
668     // returns true if the store conditional is allowed; the global monitor will
669     // still have to be checked to see whether the memory should be updated.
670     void NotifyLoad();
671     void NotifyLoadLinked(uintptr_t addr, TransactionSize size);
672     void NotifyStore();
673     bool NotifyStoreConditional(uintptr_t addr, TransactionSize size);
674 
675    private:
676     void Clear();
677 
678     MonitorAccess access_state_;
679     uintptr_t tagged_addr_;
680     TransactionSize size_;
681   };
682 
683   class GlobalMonitor {
684    public:
685     class LinkedAddress {
686      public:
687       LinkedAddress();
688 
689      private:
690       friend class GlobalMonitor;
691       // These functions manage the state machine for the global monitor, but do
692       // not actually perform loads and stores.
693       void Clear_Locked();
694       void NotifyLoadLinked_Locked(uintptr_t addr);
695       void NotifyStore_Locked();
696       bool NotifyStoreConditional_Locked(uintptr_t addr,
697                                          bool is_requesting_thread);
698 
699       MonitorAccess access_state_;
700       uintptr_t tagged_addr_;
701       LinkedAddress* next_;
702       LinkedAddress* prev_;
703       // A scd can fail due to background cache evictions. Rather than
704       // simulating this, we'll just occasionally introduce cases where an
705       // store conditional fails. This will happen once after every
706       // kMaxFailureCounter exclusive stores.
707       static const int kMaxFailureCounter = 5;
708       int failure_counter_;
709     };
710 
711     // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
712     base::Mutex mutex;
713 
714     void NotifyLoadLinked_Locked(uintptr_t addr, LinkedAddress* linked_address);
715     void NotifyStore_Locked(LinkedAddress* linked_address);
716     bool NotifyStoreConditional_Locked(uintptr_t addr,
717                                        LinkedAddress* linked_address);
718 
719     // Called when the simulator is destroyed.
720     void RemoveLinkedAddress(LinkedAddress* linked_address);
721 
722     static GlobalMonitor* Get();
723 
724    private:
725     // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
726     GlobalMonitor() = default;
727     friend class base::LeakyObject<GlobalMonitor>;
728 
729     bool IsProcessorInLinkedList_Locked(LinkedAddress* linked_address) const;
730     void PrependProcessor_Locked(LinkedAddress* linked_address);
731 
732     LinkedAddress* head_ = nullptr;
733   };
734 
735   LocalMonitor local_monitor_;
736   GlobalMonitor::LinkedAddress global_monitor_thread_;
737 };
738 
739 }  // namespace internal
740 }  // namespace v8
741 
742 #endif  // defined(USE_SIMULATOR)
743 #endif  // V8_EXECUTION_MIPS64_SIMULATOR_MIPS64_H_
744