• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 loongisa instructions if we are not generating a
6 // native loongisa binary. This Simulator allows us to run and debug loongisa
7 // code generation on regular desktop machines. V8 calls into generated code via
8 // the GeneratedCode wrapper, which will start execution in the Simulator or
9 // forwards to the real entry on a loongisa HW platform.
10 
11 #ifndef V8_EXECUTION_LOONG64_SIMULATOR_LOONG64_H_
12 #define V8_EXECUTION_LOONG64_SIMULATOR_LOONG64_H_
13 
14 // globals.h defines USE_SIMULATOR.
15 #include "src/common/globals.h"
16 
17 template <typename T>
Compare(const T & a,const T & b)18 int Compare(const T& a, const T& b) {
19   if (a == b)
20     return 0;
21   else if (a < b)
22     return -1;
23   else
24     return 1;
25 }
26 
27 // Returns the negative absolute value of its argument.
28 template <typename T,
29           typename = typename std::enable_if<std::is_signed<T>::value>::type>
Nabs(T a)30 T Nabs(T a) {
31   return a < 0 ? a : -a;
32 }
33 
34 #if defined(USE_SIMULATOR)
35 // Running with a simulator.
36 
37 #include "src/base/hashmap.h"
38 #include "src/base/strings.h"
39 #include "src/codegen/assembler.h"
40 #include "src/codegen/loong64/constants-loong64.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 Loong64Debugger;
112 
113   // Registers are declared in order.
114   enum Register {
115     no_reg = -1,
116     zero_reg = 0,
117     ra,
118     gp,
119     sp,
120     a0,
121     a1,
122     a2,
123     a3,
124     a4,
125     a5,
126     a6,
127     a7,
128     t0,
129     t1,
130     t2,
131     t3,
132     t4,
133     t5,
134     t6,
135     t7,
136     t8,
137     tp,
138     fp,
139     s0,
140     s1,
141     s2,
142     s3,
143     s4,
144     s5,
145     s6,
146     s7,
147     s8,
148     pc,  // pc must be the last register.
149     kNumSimuRegisters,
150     // aliases
151     v0 = a0,
152     v1 = a1
153   };
154 
155   // Condition flag registers.
156   enum CFRegister {
157     fcc0,
158     fcc1,
159     fcc2,
160     fcc3,
161     fcc4,
162     fcc5,
163     fcc6,
164     fcc7,
165     kNumCFRegisters
166   };
167 
168   // Floating point registers.
169   enum FPURegister {
170     f0,
171     f1,
172     f2,
173     f3,
174     f4,
175     f5,
176     f6,
177     f7,
178     f8,
179     f9,
180     f10,
181     f11,
182     f12,
183     f13,
184     f14,
185     f15,
186     f16,
187     f17,
188     f18,
189     f19,
190     f20,
191     f21,
192     f22,
193     f23,
194     f24,
195     f25,
196     f26,
197     f27,
198     f28,
199     f29,
200     f30,
201     f31,
202     kNumFPURegisters
203   };
204 
205   explicit Simulator(Isolate* isolate);
206   ~Simulator();
207 
208   // The currently executing Simulator instance. Potentially there can be one
209   // for each native thread.
210   V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate);
211 
212   // Accessors for register state. Reading the pc value adheres to the LOONG64
213   // architecture specification and is off by a 8 from the currently executing
214   // instruction.
215   void set_register(int reg, int64_t value);
216   void set_register_word(int reg, int32_t value);
217   void set_dw_register(int dreg, const int* dbl);
218   V8_EXPORT_PRIVATE int64_t get_register(int reg) const;
219   double get_double_from_register_pair(int reg);
220   // Same for FPURegisters.
221   void set_fpu_register(int fpureg, int64_t value);
222   void set_fpu_register_word(int fpureg, int32_t value);
223   void set_fpu_register_hi_word(int fpureg, int32_t value);
224   void set_fpu_register_float(int fpureg, float value);
225   void set_fpu_register_double(int fpureg, double value);
226   void set_fpu_register_invalid_result64(float original, float rounded);
227   void set_fpu_register_invalid_result(float original, float rounded);
228   void set_fpu_register_word_invalid_result(float original, float rounded);
229   void set_fpu_register_invalid_result64(double original, double rounded);
230   void set_fpu_register_invalid_result(double original, double rounded);
231   void set_fpu_register_word_invalid_result(double original, double rounded);
232   int64_t get_fpu_register(int fpureg) const;
233   int32_t get_fpu_register_word(int fpureg) const;
234   int32_t get_fpu_register_signed_word(int fpureg) const;
235   int32_t get_fpu_register_hi_word(int fpureg) const;
236   float get_fpu_register_float(int fpureg) const;
237   double get_fpu_register_double(int fpureg) const;
238   void set_cf_register(int cfreg, bool value);
239   bool get_cf_register(int cfreg) const;
240   void set_fcsr_rounding_mode(FPURoundingMode mode);
241   unsigned int get_fcsr_rounding_mode();
242   void set_fcsr_bit(uint32_t cc, bool value);
243   bool test_fcsr_bit(uint32_t cc);
244   bool set_fcsr_round_error(double original, double rounded);
245   bool set_fcsr_round64_error(double original, double rounded);
246   bool set_fcsr_round_error(float original, float rounded);
247   bool set_fcsr_round64_error(float original, float rounded);
248   void round_according_to_fcsr(double toRound, double* rounded,
249                                int32_t* rounded_int);
250   void round64_according_to_fcsr(double toRound, double* rounded,
251                                  int64_t* rounded_int);
252   void round_according_to_fcsr(float toRound, float* rounded,
253                                int32_t* rounded_int);
254   void round64_according_to_fcsr(float toRound, float* rounded,
255                                  int64_t* rounded_int);
256   // Special case of set_register and get_register to access the raw PC value.
257   void set_pc(int64_t value);
258   V8_EXPORT_PRIVATE int64_t get_pc() const;
259 
get_sp()260   Address get_sp() const { return static_cast<Address>(get_register(sp)); }
261 
262   // Accessor to the internal simulator stack area.
263   uintptr_t StackLimit(uintptr_t c_limit) const;
264 
265   // Executes LOONG64 instructions until the PC reaches end_sim_pc.
266   void Execute();
267 
268   template <typename Return, typename... Args>
Call(Address entry,Args...args)269   Return Call(Address entry, Args... args) {
270     return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
271   }
272 
273   // Alternative: call a 2-argument double function.
274   double CallFP(Address entry, double d0, double d1);
275 
276   // Push an address onto the JS stack.
277   uintptr_t PushAddress(uintptr_t address);
278 
279   // Pop an address from the JS stack.
280   uintptr_t PopAddress();
281 
282   // Debugger input.
283   void set_last_debugger_input(char* input);
last_debugger_input()284   char* last_debugger_input() { return last_debugger_input_; }
285 
286   // Redirection support.
287   static void SetRedirectInstruction(Instruction* instruction);
288 
289   // ICache checking.
290   static bool ICacheMatch(void* one, void* two);
291   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
292                           size_t size);
293 
294   // Returns true if pc register contains one of the 'special_values' defined
295   // below (bad_ra, end_sim_pc).
296   bool has_bad_pc() const;
297 
298  private:
299   enum special_values {
300     // Known bad pc value to ensure that the simulator does not execute
301     // without being properly setup.
302     bad_ra = -1,
303     // A pc value used to signal the simulator to stop execution.  Generally
304     // the ra is set to this value on transition from native C code to
305     // simulated execution, so that the simulator can "return" to the native
306     // C code.
307     end_sim_pc = -2,
308     // Unpredictable value.
309     Unpredictable = 0xbadbeaf
310   };
311 
312   V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
313                                       const intptr_t* arguments);
314 
315   // Unsupported instructions use Format to print an error and stop execution.
316   void Format(Instruction* instr, const char* format);
317 
318   // Helpers for data value tracing.
319   enum TraceType {
320     BYTE,
321     HALF,
322     WORD,
323     DWORD,
324     FLOAT,
325     DOUBLE,
326     FLOAT_DOUBLE,
327     WORD_DWORD
328   };
329 
330   // Read and write memory.
331   inline uint32_t ReadBU(int64_t addr);
332   inline int32_t ReadB(int64_t addr);
333   inline void WriteB(int64_t addr, uint8_t value);
334   inline void WriteB(int64_t addr, int8_t value);
335 
336   inline uint16_t ReadHU(int64_t addr, Instruction* instr);
337   inline int16_t ReadH(int64_t addr, Instruction* instr);
338   // Note: Overloaded on the sign of the value.
339   inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
340   inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
341 
342   inline uint32_t ReadWU(int64_t addr, Instruction* instr);
343   inline int32_t ReadW(int64_t addr, Instruction* instr, TraceType t = WORD);
344   inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
345   void WriteConditionalW(int64_t addr, int32_t value, Instruction* instr,
346                          int32_t rt_reg);
347   inline int64_t Read2W(int64_t addr, Instruction* instr);
348   inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
349   inline void WriteConditional2W(int64_t addr, int64_t value,
350                                  Instruction* instr, int32_t rt_reg);
351 
352   inline double ReadD(int64_t addr, Instruction* instr);
353   inline void WriteD(int64_t addr, double value, Instruction* instr);
354 
355   template <typename T>
356   T ReadMem(int64_t addr, Instruction* instr);
357   template <typename T>
358   void WriteMem(int64_t addr, T value, Instruction* instr);
359 
360   // Helper for debugging memory access.
361   inline void DieOrDebug();
362 
363   void TraceRegWr(int64_t value, TraceType t = DWORD);
364   void TraceMemWr(int64_t addr, int64_t value, TraceType t);
365   void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD);
366   template <typename T>
367   void TraceMemRd(int64_t addr, T value);
368   template <typename T>
369   void TraceMemWr(int64_t addr, T value);
370 
371   SimInstruction instr_;
372 
373   // Executing is handled based on the instruction type.
374   void DecodeTypeOp6();
375   void DecodeTypeOp7();
376   void DecodeTypeOp8();
377   void DecodeTypeOp10();
378   void DecodeTypeOp12();
379   void DecodeTypeOp14();
380   void DecodeTypeOp17();
381   void DecodeTypeOp22();
382 
rj_reg()383   inline int32_t rj_reg() const { return instr_.RjValue(); }
rj()384   inline int64_t rj() const { return get_register(rj_reg()); }
rj_u()385   inline uint64_t rj_u() const {
386     return static_cast<uint64_t>(get_register(rj_reg()));
387   }
rk_reg()388   inline int32_t rk_reg() const { return instr_.RkValue(); }
rk()389   inline int64_t rk() const { return get_register(rk_reg()); }
rk_u()390   inline uint64_t rk_u() const {
391     return static_cast<uint64_t>(get_register(rk_reg()));
392   }
rd_reg()393   inline int32_t rd_reg() const { return instr_.RdValue(); }
rd()394   inline int64_t rd() const { return get_register(rd_reg()); }
rd_u()395   inline uint64_t rd_u() const {
396     return static_cast<uint64_t>(get_register(rd_reg()));
397   }
fa_reg()398   inline int32_t fa_reg() const { return instr_.FaValue(); }
fa_float()399   inline float fa_float() const { return get_fpu_register_float(fa_reg()); }
fa_double()400   inline double fa_double() const { return get_fpu_register_double(fa_reg()); }
fj_reg()401   inline int32_t fj_reg() const { return instr_.FjValue(); }
fj_float()402   inline float fj_float() const { return get_fpu_register_float(fj_reg()); }
fj_double()403   inline double fj_double() const { return get_fpu_register_double(fj_reg()); }
fk_reg()404   inline int32_t fk_reg() const { return instr_.FkValue(); }
fk_float()405   inline float fk_float() const { return get_fpu_register_float(fk_reg()); }
fk_double()406   inline double fk_double() const { return get_fpu_register_double(fk_reg()); }
fd_reg()407   inline int32_t fd_reg() const { return instr_.FdValue(); }
fd_float()408   inline float fd_float() const { return get_fpu_register_float(fd_reg()); }
fd_double()409   inline double fd_double() const { return get_fpu_register_double(fd_reg()); }
cj_reg()410   inline int32_t cj_reg() const { return instr_.CjValue(); }
cj()411   inline bool cj() const { return get_cf_register(cj_reg()); }
cd_reg()412   inline int32_t cd_reg() const { return instr_.CdValue(); }
cd()413   inline bool cd() const { return get_cf_register(cd_reg()); }
ca_reg()414   inline int32_t ca_reg() const { return instr_.CaValue(); }
ca()415   inline bool ca() const { return get_cf_register(ca_reg()); }
sa2()416   inline uint32_t sa2() const { return instr_.Sa2Value(); }
sa3()417   inline uint32_t sa3() const { return instr_.Sa3Value(); }
ui5()418   inline uint32_t ui5() const { return instr_.Ui5Value(); }
ui6()419   inline uint32_t ui6() const { return instr_.Ui6Value(); }
lsbw()420   inline uint32_t lsbw() const { return instr_.LsbwValue(); }
msbw()421   inline uint32_t msbw() const { return instr_.MsbwValue(); }
lsbd()422   inline uint32_t lsbd() const { return instr_.LsbdValue(); }
msbd()423   inline uint32_t msbd() const { return instr_.MsbdValue(); }
cond()424   inline uint32_t cond() const { return instr_.CondValue(); }
si12()425   inline int32_t si12() const { return (instr_.Si12Value() << 20) >> 20; }
ui12()426   inline uint32_t ui12() const { return instr_.Ui12Value(); }
si14()427   inline int32_t si14() const { return (instr_.Si14Value() << 18) >> 18; }
si16()428   inline int32_t si16() const { return (instr_.Si16Value() << 16) >> 16; }
si20()429   inline int32_t si20() const { return (instr_.Si20Value() << 12) >> 12; }
430 
SetResult(const int32_t rd_reg,const int64_t alu_out)431   inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
432     set_register(rd_reg, alu_out);
433     TraceRegWr(alu_out);
434   }
435 
SetFPUWordResult(int32_t fd_reg,int32_t alu_out)436   inline void SetFPUWordResult(int32_t fd_reg, int32_t alu_out) {
437     set_fpu_register_word(fd_reg, alu_out);
438     TraceRegWr(get_fpu_register(fd_reg), WORD);
439   }
440 
SetFPUWordResult2(int32_t fd_reg,int32_t alu_out)441   inline void SetFPUWordResult2(int32_t fd_reg, int32_t alu_out) {
442     set_fpu_register_word(fd_reg, alu_out);
443     TraceRegWr(get_fpu_register(fd_reg));
444   }
445 
SetFPUResult(int32_t fd_reg,int64_t alu_out)446   inline void SetFPUResult(int32_t fd_reg, int64_t alu_out) {
447     set_fpu_register(fd_reg, alu_out);
448     TraceRegWr(get_fpu_register(fd_reg));
449   }
450 
SetFPUResult2(int32_t fd_reg,int64_t alu_out)451   inline void SetFPUResult2(int32_t fd_reg, int64_t alu_out) {
452     set_fpu_register(fd_reg, alu_out);
453     TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
454   }
455 
SetFPUFloatResult(int32_t fd_reg,float alu_out)456   inline void SetFPUFloatResult(int32_t fd_reg, float alu_out) {
457     set_fpu_register_float(fd_reg, alu_out);
458     TraceRegWr(get_fpu_register(fd_reg), FLOAT);
459   }
460 
SetFPUDoubleResult(int32_t fd_reg,double alu_out)461   inline void SetFPUDoubleResult(int32_t fd_reg, double alu_out) {
462     set_fpu_register_double(fd_reg, alu_out);
463     TraceRegWr(get_fpu_register(fd_reg), DOUBLE);
464   }
465 
466   // Used for breakpoints.
467   void SoftwareInterrupt();
468 
469   // Stop helper functions.
470   bool IsWatchpoint(uint64_t code);
471   void PrintWatchpoint(uint64_t code);
472   void HandleStop(uint64_t code, Instruction* instr);
473   bool IsStopInstruction(Instruction* instr);
474   bool IsEnabledStop(uint64_t code);
475   void EnableStop(uint64_t code);
476   void DisableStop(uint64_t code);
477   void IncreaseStopCounter(uint64_t code);
478   void PrintStopInfo(uint64_t code);
479 
480   // Executes one instruction.
481   void InstructionDecode(Instruction* instr);
482   // Execute one instruction placed in a branch delay slot.
483 
484   // ICache.
485   static void CheckICache(base::CustomMatcherHashMap* i_cache,
486                           Instruction* instr);
487   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
488                            size_t size);
489   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
490                                  void* page);
491 
492   enum Exception {
493     none,
494     kIntegerOverflow,
495     kIntegerUnderflow,
496     kDivideByZero,
497     kNumExceptions
498   };
499 
500   // Exceptions.
501   void SignalException(Exception e);
502 
503   // Handle arguments and return value for runtime FP functions.
504   void GetFpArgs(double* x, double* y, int32_t* z);
505   void SetFpResult(const double& result);
506 
507   void CallInternal(Address entry);
508 
509   // Architecture state.
510   // Registers.
511   int64_t registers_[kNumSimuRegisters];
512   // Floating point Registers.
513   int64_t FPUregisters_[kNumFPURegisters];
514   // Condition flags Registers.
515   bool CFregisters_[kNumCFRegisters];
516   // FPU control register.
517   uint32_t FCSR_;
518 
519   // Simulator support.
520   // Allocate 1MB for stack.
521   size_t stack_size_;
522   char* stack_;
523   bool pc_modified_;
524   int64_t icount_;
525   int break_count_;
526   base::EmbeddedVector<char, 128> trace_buf_;
527 
528   // Debugger input.
529   char* last_debugger_input_;
530 
531   v8::internal::Isolate* isolate_;
532 
533   // Registered breakpoints.
534   Instruction* break_pc_;
535   Instr break_instr_;
536 
537   // Stop is disabled if bit 31 is set.
538   static const uint32_t kStopDisabledBit = 1 << 31;
539 
540   // A stop is enabled, meaning the simulator will stop when meeting the
541   // instruction, if bit 31 of watched_stops_[code].count is unset.
542   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
543   // the breakpoint was hit or gone through.
544   struct StopCountAndDesc {
545     uint32_t count;
546     char* desc;
547   };
548   StopCountAndDesc watched_stops_[kMaxStopCode + 1];
549 
550   // Synchronization primitives.
551   enum class MonitorAccess {
552     Open,
553     RMW,
554   };
555 
556   enum class TransactionSize {
557     None = 0,
558     Word = 4,
559     DoubleWord = 8,
560   };
561 
562   // The least-significant bits of the address are ignored. The number of bits
563   // is implementation-defined, between 3 and minimum page size.
564   static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 3) - 1);
565 
566   class LocalMonitor {
567    public:
568     LocalMonitor();
569 
570     // These functions manage the state machine for the local monitor, but do
571     // not actually perform loads and stores. NotifyStoreConditional only
572     // returns true if the store conditional is allowed; the global monitor will
573     // still have to be checked to see whether the memory should be updated.
574     void NotifyLoad();
575     void NotifyLoadLinked(uintptr_t addr, TransactionSize size);
576     void NotifyStore();
577     bool NotifyStoreConditional(uintptr_t addr, TransactionSize size);
578 
579    private:
580     void Clear();
581 
582     MonitorAccess access_state_;
583     uintptr_t tagged_addr_;
584     TransactionSize size_;
585   };
586 
587   class GlobalMonitor {
588    public:
589     class LinkedAddress {
590      public:
591       LinkedAddress();
592 
593      private:
594       friend class GlobalMonitor;
595       // These functions manage the state machine for the global monitor, but do
596       // not actually perform loads and stores.
597       void Clear_Locked();
598       void NotifyLoadLinked_Locked(uintptr_t addr);
599       void NotifyStore_Locked();
600       bool NotifyStoreConditional_Locked(uintptr_t addr,
601                                          bool is_requesting_thread);
602 
603       MonitorAccess access_state_;
604       uintptr_t tagged_addr_;
605       LinkedAddress* next_;
606       LinkedAddress* prev_;
607       // A scd can fail due to background cache evictions. Rather than
608       // simulating this, we'll just occasionally introduce cases where an
609       // store conditional fails. This will happen once after every
610       // kMaxFailureCounter exclusive stores.
611       static const int kMaxFailureCounter = 5;
612       int failure_counter_;
613     };
614 
615     // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
616     base::Mutex mutex;
617 
618     void NotifyLoadLinked_Locked(uintptr_t addr, LinkedAddress* linked_address);
619     void NotifyStore_Locked(LinkedAddress* linked_address);
620     bool NotifyStoreConditional_Locked(uintptr_t addr,
621                                        LinkedAddress* linked_address);
622 
623     // Called when the simulator is destroyed.
624     void RemoveLinkedAddress(LinkedAddress* linked_address);
625 
626     static GlobalMonitor* Get();
627 
628    private:
629     // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
630     GlobalMonitor() = default;
631     friend class base::LeakyObject<GlobalMonitor>;
632 
633     bool IsProcessorInLinkedList_Locked(LinkedAddress* linked_address) const;
634     void PrependProcessor_Locked(LinkedAddress* linked_address);
635 
636     LinkedAddress* head_ = nullptr;
637   };
638 
639   LocalMonitor local_monitor_;
640   GlobalMonitor::LinkedAddress global_monitor_thread_;
641 };
642 
643 }  // namespace internal
644 }  // namespace v8
645 
646 #endif  // defined(USE_SIMULATOR)
647 #endif  // V8_EXECUTION_LOONG64_SIMULATOR_LOONG64_H_
648