Simulator-loong64.h (20693B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright 2020 the V8 project authors. All rights reserved. 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following 12 // disclaimer in the documentation and/or other materials provided 13 // with the distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived 16 // from this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #ifndef jit_loong64_Simulator_loong64_h 31 #define jit_loong64_Simulator_loong64_h 32 33 #ifdef JS_SIMULATOR_LOONG64 34 35 # include "mozilla/Atomics.h" 36 37 # include "jit/IonTypes.h" 38 # include "js/ProfilingFrameIterator.h" 39 # include "threading/Thread.h" 40 # include "vm/MutexIDs.h" 41 # include "wasm/WasmSignalHandlers.h" 42 43 namespace js { 44 45 namespace jit { 46 47 class JitActivation; 48 49 class Simulator; 50 class Redirection; 51 class CachePage; 52 class AutoLockSimulator; 53 54 // When the SingleStepCallback is called, the simulator is about to execute 55 // sim->get_pc() and the current machine state represents the completed 56 // execution of the previous pc. 57 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc); 58 59 const intptr_t kPointerAlignment = 8; 60 const intptr_t kPointerAlignmentMask = kPointerAlignment - 1; 61 62 const intptr_t kDoubleAlignment = 8; 63 const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1; 64 65 // Number of general purpose registers. 66 const int kNumRegisters = 32; 67 68 // In the simulator, the PC register is simulated as the 34th register. 69 const int kPCRegister = 32; 70 71 // Number coprocessor registers. 72 const int kNumFPURegisters = 32; 73 74 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented. 75 // TODO fcsr0 fcsr1 fcsr2 fcsr3 76 const int kFCSRRegister = 0; 77 const int kInvalidFPUControlRegister = -1; 78 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1; 79 const int32_t kFPUInvalidResultNegative = static_cast<int32_t>(1u << 31); 80 const uint64_t kFPU64InvalidResult = 81 static_cast<uint64_t>(static_cast<uint64_t>(1) << 63) - 1; 82 const int64_t kFPU64InvalidResultNegative = 83 static_cast<int64_t>(static_cast<uint64_t>(1) << 63); 84 85 const uint32_t kFPURoundingModeShift = 8; 86 const uint32_t kFPURoundingModeMask = 0b11 << kFPURoundingModeShift; 87 88 // FPU rounding modes. 89 enum FPURoundingMode { 90 RN = 0b00 << kFPURoundingModeShift, // Round to Nearest. 91 RZ = 0b01 << kFPURoundingModeShift, // Round towards zero. 92 RP = 0b10 << kFPURoundingModeShift, // Round towards Plus Infinity. 93 RM = 0b11 << kFPURoundingModeShift, // Round towards Minus Infinity. 94 95 // Aliases. 96 kRoundToNearest = RN, 97 kRoundToZero = RZ, 98 kRoundToPlusInf = RP, 99 kRoundToMinusInf = RM, 100 101 mode_round = RN, 102 mode_ceil = RP, 103 mode_floor = RM, 104 mode_trunc = RZ 105 }; 106 107 // FCSR constants. 108 const uint32_t kFCSRInexactFlagBit = 16; 109 const uint32_t kFCSRUnderflowFlagBit = 17; 110 const uint32_t kFCSROverflowFlagBit = 18; 111 const uint32_t kFCSRDivideByZeroFlagBit = 19; 112 const uint32_t kFCSRInvalidOpFlagBit = 20; 113 114 const uint32_t kFCSRInexactCauseBit = 24; 115 const uint32_t kFCSRUnderflowCauseBit = 25; 116 const uint32_t kFCSROverflowCauseBit = 26; 117 const uint32_t kFCSRDivideByZeroCauseBit = 27; 118 const uint32_t kFCSRInvalidOpCauseBit = 28; 119 120 const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit; 121 const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit; 122 const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit; 123 const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit; 124 const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit; 125 126 const uint32_t kFCSRFlagMask = 127 kFCSRInexactFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowFlagMask | 128 kFCSRDivideByZeroFlagMask | kFCSRInvalidOpFlagMask; 129 130 const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask; 131 132 // On LoongArch64 Simulator breakpoints can have different codes: 133 // - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints, 134 // the simulator will run through them and print the registers. 135 // - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop() 136 // instructions (see Assembler::stop()). 137 // - Breaks larger than kMaxStopCode are simple breaks, dropping you into the 138 // debugger. 139 const uint32_t kMaxWatchpointCode = 31; 140 const uint32_t kMaxStopCode = 127; 141 const uint32_t kWasmTrapCode = 6; 142 143 // ----------------------------------------------------------------------------- 144 // Utility functions 145 146 typedef uint32_t Instr; 147 class SimInstruction; 148 149 // Per thread simulator state. 150 class Simulator { 151 friend class loong64Debugger; 152 153 public: 154 // Registers are declared in order. 155 enum Register { 156 no_reg = -1, 157 zero_reg = 0, 158 ra, 159 gp, 160 sp, 161 a0, 162 a1, 163 a2, 164 a3, 165 a4, 166 a5, 167 a6, 168 a7, 169 t0, 170 t1, 171 t2, 172 t3, 173 t4, 174 t5, 175 t6, 176 t7, 177 t8, 178 tp, 179 fp, 180 s0, 181 s1, 182 s2, 183 s3, 184 s4, 185 s5, 186 s6, 187 s7, 188 s8, 189 pc, // pc must be the last register. 190 kNumSimuRegisters, 191 // aliases 192 v0 = a0, 193 v1 = a1, 194 }; 195 196 // Condition flag registers. 197 enum CFRegister { 198 fcc0, 199 fcc1, 200 fcc2, 201 fcc3, 202 fcc4, 203 fcc5, 204 fcc6, 205 fcc7, 206 kNumCFRegisters 207 }; 208 209 // Floating point registers. 210 enum FPURegister { 211 f0, 212 f1, 213 f2, 214 f3, 215 f4, 216 f5, 217 f6, 218 f7, 219 f8, 220 f9, 221 f10, 222 f11, 223 f12, 224 f13, 225 f14, 226 f15, 227 f16, 228 f17, 229 f18, 230 f19, 231 f20, 232 f21, 233 f22, 234 f23, 235 f24, 236 f25, 237 f26, 238 f27, 239 f28, 240 f29, 241 f30, 242 f31, 243 kNumFPURegisters 244 }; 245 246 // Returns nullptr on OOM. 247 static Simulator* Create(); 248 249 static void Destroy(Simulator* simulator); 250 251 // Constructor/destructor are for internal use only; use the static methods 252 // above. 253 Simulator(); 254 ~Simulator(); 255 256 // The currently executing Simulator instance. Potentially there can be one 257 // for each native thread. 258 static Simulator* Current(); 259 260 static inline uintptr_t StackLimit() { 261 return Simulator::Current()->stackLimit(); 262 } 263 264 uintptr_t* addressOfStackLimit(); 265 266 // Accessors for register state. Reading the pc value adheres to the LOONG64 267 // architecture specification and is off by a 8 from the currently executing 268 // instruction. 269 void setRegister(int reg, int64_t value); 270 int64_t getRegister(int reg) const; 271 // Same for FPURegisters. 272 void setFpuRegister(int fpureg, int64_t value); 273 void setFpuRegisterWord(int fpureg, int32_t value); 274 void setFpuRegisterHiWord(int fpureg, int32_t value); 275 void setFpuRegisterFloat(int fpureg, float value); 276 void setFpuRegisterDouble(int fpureg, double value); 277 278 void setFpuRegisterWordInvalidResult(float original, float rounded, 279 int fpureg); 280 void setFpuRegisterWordInvalidResult(double original, double rounded, 281 int fpureg); 282 void setFpuRegisterInvalidResult(float original, float rounded, int fpureg); 283 void setFpuRegisterInvalidResult(double original, double rounded, int fpureg); 284 void setFpuRegisterInvalidResult64(float original, float rounded, int fpureg); 285 void setFpuRegisterInvalidResult64(double original, double rounded, 286 int fpureg); 287 288 int64_t getFpuRegister(int fpureg) const; 289 // int32_t getFpuRegisterLo(int fpureg) const; 290 // int32_t getFpuRegisterHi(int fpureg) const; 291 int32_t getFpuRegisterWord(int fpureg) const; 292 int32_t getFpuRegisterSignedWord(int fpureg) const; 293 int32_t getFpuRegisterHiWord(int fpureg) const; 294 float getFpuRegisterFloat(int fpureg) const; 295 double getFpuRegisterDouble(int fpureg) const; 296 297 void setCFRegister(int cfreg, bool value); 298 bool getCFRegister(int cfreg) const; 299 300 void set_fcsr_rounding_mode(FPURoundingMode mode); 301 302 void setFCSRBit(uint32_t cc, bool value); 303 bool testFCSRBit(uint32_t cc); 304 unsigned int getFCSRRoundingMode(); 305 template <typename T> 306 bool setFCSRRoundError(double original, double rounded); 307 bool setFCSRRound64Error(float original, float rounded); 308 309 template <typename T> 310 void roundAccordingToFCSR(T toRound, T* rounded, int32_t* rounded_int); 311 312 template <typename T> 313 void round64AccordingToFCSR(T toRound, T* rounded, int64_t* rounded_int); 314 315 // Special case of set_register and get_register to access the raw PC value. 316 void set_pc(int64_t value); 317 int64_t get_pc() const; 318 319 template <typename T> 320 T get_pc_as() const { 321 return reinterpret_cast<T>(get_pc()); 322 } 323 324 void enable_single_stepping(SingleStepCallback cb, void* arg); 325 void disable_single_stepping(); 326 327 // Accessor to the internal simulator stack area. 328 uintptr_t stackLimit() const; 329 bool overRecursed(uintptr_t newsp = 0) const; 330 bool overRecursedWithExtra(uint32_t extra) const; 331 332 // Executes LOONG64 instructions until the PC reaches end_sim_pc. 333 template <bool enableStopSimAt> 334 void execute(); 335 336 // Sets up the simulator state and grabs the result on return. 337 int64_t call(uint8_t* entry, int argument_count, ...); 338 339 // Push an address onto the JS stack. 340 uintptr_t pushAddress(uintptr_t address); 341 342 // Pop an address from the JS stack. 343 uintptr_t popAddress(); 344 345 // Debugger input. 346 void setLastDebuggerInput(char* input); 347 char* lastDebuggerInput() { return lastDebuggerInput_; } 348 349 // Returns true if pc register contains one of the 'SpecialValues' defined 350 // below (bad_ra, end_sim_pc). 351 bool has_bad_pc() const; 352 353 private: 354 enum SpecialValues { 355 // Known bad pc value to ensure that the simulator does not execute 356 // without being properly setup. 357 bad_ra = -1, 358 // A pc value used to signal the simulator to stop execution. Generally 359 // the ra is set to this value on transition from native C code to 360 // simulated execution, so that the simulator can "return" to the native 361 // C code. 362 end_sim_pc = -2, 363 // Unpredictable value. 364 Unpredictable = 0xbadbeaf 365 }; 366 367 bool init(); 368 369 // Unsupported instructions use Format to print an error and stop execution. 370 void format(SimInstruction* instr, const char* format); 371 372 // Read and write memory. 373 inline uint8_t readBU(uint64_t addr); 374 inline int8_t readB(uint64_t addr); 375 inline void writeB(uint64_t addr, uint8_t value); 376 inline void writeB(uint64_t addr, int8_t value); 377 378 inline uint16_t readHU(uint64_t addr, SimInstruction* instr); 379 inline int16_t readH(uint64_t addr, SimInstruction* instr); 380 inline void writeH(uint64_t addr, uint16_t value, SimInstruction* instr); 381 inline void writeH(uint64_t addr, int16_t value, SimInstruction* instr); 382 383 inline uint32_t readWU(uint64_t addr, SimInstruction* instr); 384 inline int32_t readW(uint64_t addr, SimInstruction* instr); 385 inline void writeW(uint64_t addr, uint32_t value, SimInstruction* instr); 386 inline void writeW(uint64_t addr, int32_t value, SimInstruction* instr); 387 388 inline int64_t readDW(uint64_t addr, SimInstruction* instr); 389 inline void writeDW(uint64_t addr, int64_t value, SimInstruction* instr); 390 391 inline double readD(uint64_t addr, SimInstruction* instr); 392 inline void writeD(uint64_t addr, double value, SimInstruction* instr); 393 394 inline int32_t loadLinkedW(uint64_t addr, SimInstruction* instr); 395 inline int storeConditionalW(uint64_t addr, int32_t value, 396 SimInstruction* instr); 397 398 inline int64_t loadLinkedD(uint64_t addr, SimInstruction* instr); 399 inline int storeConditionalD(uint64_t addr, int64_t value, 400 SimInstruction* instr); 401 402 // Executing is handled based on the instruction type. 403 void decodeTypeOp6(SimInstruction* instr); 404 void decodeTypeOp7(SimInstruction* instr); 405 void decodeTypeOp8(SimInstruction* instr); 406 void decodeTypeOp10(SimInstruction* instr); 407 void decodeTypeOp11(SimInstruction* instr); 408 void decodeTypeOp12(SimInstruction* instr); 409 void decodeTypeOp14(SimInstruction* instr); 410 void decodeTypeOp15(SimInstruction* instr); 411 void decodeTypeOp16(SimInstruction* instr); 412 void decodeTypeOp17(SimInstruction* instr); 413 void decodeTypeOp22(SimInstruction* instr); 414 void decodeTypeOp24(SimInstruction* instr); 415 416 inline int32_t rj_reg(SimInstruction* instr) const; 417 inline int64_t rj(SimInstruction* instr) const; 418 inline uint64_t rj_u(SimInstruction* instr) const; 419 inline int32_t rk_reg(SimInstruction* instr) const; 420 inline int64_t rk(SimInstruction* instr) const; 421 inline uint64_t rk_u(SimInstruction* instr) const; 422 inline int32_t rd_reg(SimInstruction* instr) const; 423 inline int64_t rd(SimInstruction* instr) const; 424 inline uint64_t rd_u(SimInstruction* instr) const; 425 inline int32_t fa_reg(SimInstruction* instr) const; 426 inline float fa_float(SimInstruction* instr) const; 427 inline double fa_double(SimInstruction* instr) const; 428 429 inline int32_t fj_reg(SimInstruction* instr) const; 430 inline float fj_float(SimInstruction* instr) const; 431 inline double fj_double(SimInstruction* instr) const; 432 433 inline int32_t fk_reg(SimInstruction* instr) const; 434 inline float fk_float(SimInstruction* instr) const; 435 inline double fk_double(SimInstruction* instr) const; 436 inline int32_t fd_reg(SimInstruction* instr) const; 437 inline float fd_float(SimInstruction* instr) const; 438 inline double fd_double(SimInstruction* instr) const; 439 440 inline int32_t cj_reg(SimInstruction* instr) const; 441 inline bool cj(SimInstruction* instr) const; 442 443 inline int32_t cd_reg(SimInstruction* instr) const; 444 inline bool cd(SimInstruction* instr) const; 445 446 inline int32_t ca_reg(SimInstruction* instr) const; 447 inline bool ca(SimInstruction* instr) const; 448 inline uint32_t sa2(SimInstruction* instr) const; 449 inline uint32_t sa3(SimInstruction* instr) const; 450 inline uint32_t ui5(SimInstruction* instr) const; 451 inline uint32_t ui6(SimInstruction* instr) const; 452 inline uint32_t lsbw(SimInstruction* instr) const; 453 inline uint32_t msbw(SimInstruction* instr) const; 454 inline uint32_t lsbd(SimInstruction* instr) const; 455 inline uint32_t msbd(SimInstruction* instr) const; 456 inline uint32_t cond(SimInstruction* instr) const; 457 inline int32_t si12(SimInstruction* instr) const; 458 inline uint32_t ui12(SimInstruction* instr) const; 459 inline int32_t si14(SimInstruction* instr) const; 460 inline int32_t si16(SimInstruction* instr) const; 461 inline int32_t si20(SimInstruction* instr) const; 462 463 // Used for breakpoints. 464 void softwareInterrupt(SimInstruction* instr); 465 466 // Stop helper functions. 467 bool isWatchpoint(uint32_t code); 468 void printWatchpoint(uint32_t code); 469 void handleStop(uint32_t code, SimInstruction* instr); 470 bool isStopInstruction(SimInstruction* instr); 471 bool isEnabledStop(uint32_t code); 472 void enableStop(uint32_t code); 473 void disableStop(uint32_t code); 474 void increaseStopCounter(uint32_t code); 475 void printStopInfo(uint32_t code); 476 477 JS::ProfilingFrameIterator::RegisterState registerState(); 478 479 // Handle any wasm faults, returning true if the fault was handled. 480 // This method is rather hot so inline the normal (no-wasm) case. 481 bool MOZ_ALWAYS_INLINE handleWasmSegFault(uint64_t addr, unsigned numBytes) { 482 if (MOZ_LIKELY(!js::wasm::CodeExists)) { 483 return false; 484 } 485 486 uint8_t* newPC; 487 if (!js::wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes, 488 &newPC)) { 489 return false; 490 } 491 492 LLBit_ = false; 493 set_pc(int64_t(newPC)); 494 return true; 495 } 496 497 // Executes one instruction. 498 void instructionDecode(SimInstruction* instr); 499 500 public: 501 static int64_t StopSimAt; 502 503 // Runtime call support. 504 static void* RedirectNativeFunction(void* nativeFunction, 505 ABIFunctionType type); 506 507 private: 508 enum Exception { 509 kNone, 510 kIntegerOverflow, 511 kIntegerUnderflow, 512 kDivideByZero, 513 kNumExceptions 514 }; 515 int16_t exceptions[kNumExceptions]; 516 517 // Exceptions. 518 void signalExceptions(); 519 520 // Handle return value for runtime FP functions. 521 void setCallResultDouble(double result); 522 void setCallResultFloat(float result); 523 void setCallResult(int64_t res); 524 # ifdef XP_DARWIN 525 // add a dedicated setCallResult for intptr_t on Darwin 526 void setCallResult(intptr_t res); 527 # endif 528 void setCallResult(__int128 res); 529 530 void callInternal(uint8_t* entry); 531 532 // Architecture state. 533 // Registers. 534 int64_t registers_[kNumSimuRegisters]; 535 // Floating point Registers. 536 int64_t FPUregisters_[kNumFPURegisters]; 537 // Condition flags Registers. 538 bool CFregisters_[kNumCFRegisters]; 539 // FPU control register. 540 uint32_t FCSR_; 541 542 bool LLBit_; 543 uintptr_t LLAddr_; 544 int64_t lastLLValue_; 545 546 // Simulator support. 547 char* stack_; 548 uintptr_t stackLimit_; 549 bool pc_modified_; 550 int64_t icount_; 551 int64_t break_count_; 552 553 // Debugger input. 554 char* lastDebuggerInput_; 555 556 // Registered breakpoints. 557 SimInstruction* break_pc_; 558 Instr break_instr_; 559 560 // Single-stepping support 561 bool single_stepping_; 562 SingleStepCallback single_step_callback_; 563 void* single_step_callback_arg_; 564 565 // A stop is watched if its code is less than kNumOfWatchedStops. 566 // Only watched stops support enabling/disabling and the counter feature. 567 static const uint32_t kNumOfWatchedStops = 256; 568 569 // Stop is disabled if bit 31 is set. 570 static const uint32_t kStopDisabledBit = 1U << 31; 571 572 // A stop is enabled, meaning the simulator will stop when meeting the 573 // instruction, if bit 31 of watchedStops_[code].count is unset. 574 // The value watchedStops_[code].count & ~(1 << 31) indicates how many times 575 // the breakpoint was hit or gone through. 576 struct StopCountAndDesc { 577 uint32_t count_; 578 char* desc_; 579 }; 580 StopCountAndDesc watchedStops_[kNumOfWatchedStops]; 581 }; 582 583 // Process wide simulator state. 584 class SimulatorProcess { 585 friend class Redirection; 586 friend class AutoLockSimulatorCache; 587 588 private: 589 // ICache checking. 590 struct ICacheHasher { 591 typedef void* Key; 592 typedef void* Lookup; 593 static HashNumber hash(const Lookup& l); 594 static bool match(const Key& k, const Lookup& l); 595 }; 596 597 public: 598 typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap; 599 600 static mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 601 ICacheCheckingDisableCount; 602 static void FlushICache(void* start, size_t size); 603 604 static void checkICacheLocked(SimInstruction* instr); 605 606 static bool initialize() { 607 singleton_ = js_new<SimulatorProcess>(); 608 return singleton_; 609 } 610 static void destroy() { 611 js_delete(singleton_); 612 singleton_ = nullptr; 613 } 614 615 SimulatorProcess(); 616 ~SimulatorProcess(); 617 618 private: 619 static SimulatorProcess* singleton_; 620 621 // This lock creates a critical section around 'redirection_' and 622 // 'icache_', which are referenced both by the execution engine 623 // and by the off-thread compiler (see Redirection::Get in the cpp file). 624 Mutex cacheLock_; 625 626 Redirection* redirection_; 627 ICacheMap icache_; 628 629 public: 630 static ICacheMap& icache() { 631 // Technically we need the lock to access the innards of the 632 // icache, not to take its address, but the latter condition 633 // serves as a useful complement to the former. 634 singleton_->cacheLock_.assertOwnedByCurrentThread(); 635 return singleton_->icache_; 636 } 637 638 static Redirection* redirection() { 639 singleton_->cacheLock_.assertOwnedByCurrentThread(); 640 return singleton_->redirection_; 641 } 642 643 static void setRedirection(js::jit::Redirection* redirection) { 644 singleton_->cacheLock_.assertOwnedByCurrentThread(); 645 singleton_->redirection_ = redirection; 646 } 647 }; 648 649 } // namespace jit 650 } // namespace js 651 652 #endif /* JS_SIMULATOR_LOONG64 */ 653 654 #endif /* jit_loong64_Simulator_loong64_h */