MCPcopy Create free account
hub / github.com/FEX-Emu/FEX / ExitFunctionLink

Method ExitFunctionLink

FEXCore/Source/Interface/Core/JIT/JIT.cpp:528–610  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

526}
527
528uint64_t Arm64JITCore::ExitFunctionLink(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) {
529 auto Thread = Frame->Thread;
530 bool TFSet = Thread->CurrentFrame->State.flags[X86State::RFLAG_TF_RAW_LOC];
531 uintptr_t HostCode {};
532 auto GuestRip = Record->GuestRIP;
533
534 if (TFSet) {
535 // If TF is set, the cache must be skipped as different code needs to be generated.
536 Frame->State.rip = GuestRip;
537 return Frame->Pointers.Common.DispatcherLoopTop;
538 } else {
539 {
540 // Guard the LookupCache lock with the code invalidation mutex, to avoid issues with forking
541 auto lk_inval = GuardSignalDeferringSection<std::shared_lock>(static_cast<Context::ContextImpl*>(Thread->CTX)->CodeInvalidationMutex, Thread);
542 HostCode = Thread->LookupCache->FindBlock(GuestRip);
543 }
544 if (!HostCode) {
545 // Hold a reference to the code buffer, to avoid linking unmapped code if compilation triggers a recreation.
546 auto CodeBuffer = static_cast<Arm64JITCore*>(Thread->CPUBackend.get())->CurrentCodeBuffer;
547 HostCode = static_cast<Context::ContextImpl*>(Thread->CTX)->CompileBlock(Frame, GuestRip, 0);
548 if (Thread->LookupCache->Shared != CodeBuffer->LookupCache.get()) {
549 return HostCode;
550 }
551 }
552 }
553
554 // See ExitFunction in BranchOps.cpp for an assembly level view of the handled cases.
555 uintptr_t JumpThunkStartAddress = reinterpret_cast<uintptr_t>(Record) - 0x10;
556 uintptr_t CallerAddress = JumpThunkStartAddress + Record->CallerOffset;
557 auto BranchOffset = HostCode / 4 - CallerAddress / 4;
558
559 uint32_t ExpectedKnownCallMarkerInst = 0;
560 ARMEmitter::Emitter ExpectedKnownCallMarkerEmit(reinterpret_cast<uint8_t*>(&ExpectedKnownCallMarkerInst), 4);
561 ExpectedKnownCallMarkerEmit.adr(TMP1, 0xC);
562
563 // Guard the LookupCache lock with the code invalidation mutex, to avoid issues with forking
564 auto lk_inval = GuardSignalDeferringSection<std::shared_lock>(static_cast<Context::ContextImpl*>(Thread->CTX)->CodeInvalidationMutex, Thread);
565
566 // Lock here is necessary to prevent simultaneous linking and delinking
567 auto lk = Thread->LookupCache->AcquireLock();
568
569 // For non-calls, this would extend into the block's code, however that's fine as an out-of-range adr would never
570 // be generated avoiding any false positives.
571 uintptr_t KnownCallMarkerAddr = CallerAddress - 0x8;
572 uint32_t KnownCallMarkerInst = *reinterpret_cast<uint32_t*>(KnownCallMarkerAddr);
573 if (ARMEmitter::Emitter::IsInt26(BranchOffset)) {
574 // Directly patch the callsite with the appropriate branch instruction.
575 uint32_t BranchInst = 0;
576 ARMEmitter::Emitter BranchEmit(reinterpret_cast<uint8_t*>(&BranchInst), 4);
577
578 if (KnownCallMarkerInst == ExpectedKnownCallMarkerInst) {
579 BranchEmit.bl(BranchOffset);
580 Thread->LookupCache->AddBlockLink(GuestRip, Record, [](FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) {
581 DirectBlockDelinker(Frame, Record, true);
582 });
583 } else {
584 BranchEmit.b(BranchOffset);
585 Thread->LookupCache->AddBlockLink(GuestRip, Record, [](FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record) {

Callers

nothing calls this directly

Calls 7

DirectBlockDelinkerFunction · 0.85
ClearICacheFunction · 0.85
getMethod · 0.80
CompileBlockMethod · 0.80
FindBlockMethod · 0.45
AcquireLockMethod · 0.45
AddBlockLinkMethod · 0.45

Tested by

no test coverage detected