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