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