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