Title: [277838] trunk/Source/_javascript_Core
Revision
277838
Author
[email protected]
Date
2021-05-20 17:14:50 -0700 (Thu, 20 May 2021)

Log Message

Make polymorphic calls play nice with Data Call ICs
https://bugs.webkit.org/show_bug.cgi?id=225793

Reviewed by Robin Morisset.

This patch makes it so that Polymorphic stubs don't repatch when using
Data Call ICs. We add a branch to the Data IC fast path to see if we're
polymorphic. If we are, then we either call or tail call the polymorphic
stub, depending on the CallLinkInfo's call type. This patch also changes
the polymorphic stub to handle being called instead of jumped to, since that
will now happen for Data ICs of non tail calls.

* bytecode/CallLinkInfo.cpp:
(JSC::CallLinkInfo::setMonomorphicCallee):
(JSC::CallLinkInfo::callee):
(JSC::CallLinkInfo::visitWeak):
(JSC::CallLinkInfo::emitFastPathImpl):
(JSC::CallLinkInfo::revertCallToStub):
(JSC::CallLinkInfo::setStub):
(JSC::CallLinkInfo::emitFirstInstructionForDataIC): Deleted.
* bytecode/CallLinkInfo.h:
* jit/Repatch.cpp:
(JSC::linkPolymorphicCall):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (277837 => 277838)


--- trunk/Source/_javascript_Core/ChangeLog	2021-05-20 23:39:30 UTC (rev 277837)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-05-21 00:14:50 UTC (rev 277838)
@@ -1,3 +1,29 @@
+2021-05-20  Saam Barati  <[email protected]>
+
+        Make polymorphic calls play nice with Data Call ICs
+        https://bugs.webkit.org/show_bug.cgi?id=225793
+
+        Reviewed by Robin Morisset.
+
+        This patch makes it so that Polymorphic stubs don't repatch when using
+        Data Call ICs. We add a branch to the Data IC fast path to see if we're
+        polymorphic. If we are, then we either call or tail call the polymorphic
+        stub, depending on the CallLinkInfo's call type. This patch also changes
+        the polymorphic stub to handle being called instead of jumped to, since that
+        will now happen for Data ICs of non tail calls.
+
+        * bytecode/CallLinkInfo.cpp:
+        (JSC::CallLinkInfo::setMonomorphicCallee):
+        (JSC::CallLinkInfo::callee):
+        (JSC::CallLinkInfo::visitWeak):
+        (JSC::CallLinkInfo::emitFastPathImpl):
+        (JSC::CallLinkInfo::revertCallToStub):
+        (JSC::CallLinkInfo::setStub):
+        (JSC::CallLinkInfo::emitFirstInstructionForDataIC): Deleted.
+        * bytecode/CallLinkInfo.h:
+        * jit/Repatch.cpp:
+        (JSC::linkPolymorphicCall):
+
 2021-05-20  Tuomas Karkkainen  <[email protected]>
 
         $vm should have a function for checking if ASan is enabled similar to $vm.assertEnabled

Modified: trunk/Source/_javascript_Core/bytecode/CallLinkInfo.cpp (277837 => 277838)


--- trunk/Source/_javascript_Core/bytecode/CallLinkInfo.cpp	2021-05-20 23:39:30 UTC (rev 277837)
+++ trunk/Source/_javascript_Core/bytecode/CallLinkInfo.cpp	2021-05-21 00:14:50 UTC (rev 277838)
@@ -131,9 +131,12 @@
     return m_doneLocation;
 }
 
+static constexpr uintptr_t polymorphicCalleeMask = 1;
+
 void CallLinkInfo::setMonomorphicCallee(VM& vm, JSCell* owner, JSObject* callee, MacroAssemblerCodePtr<JSEntryPtrTag> codePtr)
 {
     RELEASE_ASSERT(!isDirect());
+    RELEASE_ASSERT(!(bitwise_cast<uintptr_t>(callee) & polymorphicCalleeMask));
     m_calleeOrCodeBlock.set(vm, owner, callee);
 
     if (isDataIC()) 
@@ -157,6 +160,7 @@
 JSObject* CallLinkInfo::callee()
 {
     RELEASE_ASSERT(!isDirect());
+    RELEASE_ASSERT(!(bitwise_cast<uintptr_t>(m_calleeOrCodeBlock.get()) & polymorphicCalleeMask));
     return jsCast<JSObject*>(m_calleeOrCodeBlock.get());
 }
 
@@ -250,18 +254,19 @@
                         pointerDump(codeBlock()), ").\n");
                 }
             } else {
-                if (callee()->type() == JSFunctionType) {
+                JSObject* callee = jsCast<JSObject*>(m_calleeOrCodeBlock.get());
+                if (callee->type() == JSFunctionType) {
                     if (UNLIKELY(Options::verboseOSR())) {
                         dataLog(
                             "Clearing call to ",
-                            RawPointer(callee()), " (",
-                            static_cast<JSFunction*>(callee())->executable()->hashFor(specializationKind()),
+                            RawPointer(callee), " (",
+                            static_cast<JSFunction*>(callee)->executable()->hashFor(specializationKind()),
                             ").\n");
                     }
-                    handleSpecificCallee(static_cast<JSFunction*>(callee()));
+                    handleSpecificCallee(static_cast<JSFunction*>(callee));
                 } else {
                     if (UNLIKELY(Options::verboseOSR()))
-                        dataLog("Clearing call to ", RawPointer(callee()), ".\n");
+                        dataLog("Clearing call to ", RawPointer(callee), ".\n");
                     m_clearedByGC = true;
                 }
             }
@@ -293,18 +298,6 @@
     m_frameShuffleData->shrinkToFit();
 }
 
-void CallLinkInfo::emitFirstInstructionForDataIC(CCallHelpers& jit, GPRReg callLinkInfoGPR)
-{
-    GPRReg scratchGPR = jit.scratchRegister();
-    DisallowMacroScratchRegisterUsage disallowScratch(jit);
-    // When repatching, we just overwrite the first instruction back, since it'll have been replaced with a jump to the polymorphic call stub.
-    size_t startSize = jit.m_assembler.buffer().codeSize();
-    jit.loadPtr(CCallHelpers::Address(callLinkInfoGPR, offsetOfCallee()), scratchGPR); 
-    size_t loadSize = jit.m_assembler.buffer().codeSize() - startSize;
-    if (loadSize < static_cast<size_t>(CCallHelpers::patchableJumpSize()))
-        jit.emitNops(static_cast<size_t>(CCallHelpers::patchableJumpSize()) - loadSize);
-}
-
 MacroAssembler::JumpList CallLinkInfo::emitFastPathImpl(CCallHelpers& jit, GPRReg calleeGPR, GPRReg callLinkInfoGPR, UseDataIC useDataIC, WTF::Function<void()> prepareForTailCall)
 {
     setUsesDataICs(useDataIC);
@@ -323,16 +316,21 @@
 
     if (isDataIC()) {
         GPRReg scratchGPR = jit.scratchRegister();
-        emitFirstInstructionForDataIC(jit, callLinkInfoGPR);
+        jit.loadPtr(CCallHelpers::Address(callLinkInfoGPR, offsetOfCallee()), scratchGPR); 
+        CCallHelpers::Jump goPolymorphic;
         {
             DisallowMacroScratchRegisterUsage disallowScratch(jit);
+            goPolymorphic = jit.branchTestPtr(CCallHelpers::NonZero, scratchGPR, CCallHelpers::TrustedImm32(polymorphicCalleeMask));
             slowPath.append(jit.branchPtr(CCallHelpers::NotEqual, scratchGPR, calleeGPR));
         }
         if (isTailCall()) {
             prepareForTailCall();
+            goPolymorphic.link(&jit); // Polymorphic stub handles tail call stack prep.
             jit.farJump(CCallHelpers::Address(callLinkInfoGPR, offsetOfMonomorphicCallDestination()), JSEntryPtrTag);
-        } else
+        } else {
+            goPolymorphic.link(&jit);
             jit.call(CCallHelpers::Address(callLinkInfoGPR, offsetOfMonomorphicCallDestination()), JSEntryPtrTag);
+        }
     } else {
         CCallHelpers::DataLabelPtr calleeCheck;
         slowPath.append(jit.branchPtrWithPatch(CCallHelpers::NotEqual, calleeGPR, calleeCheck, CCallHelpers::TrustedImmPtr(nullptr)));
@@ -464,14 +462,13 @@
     // what in all likelihood fits in 24. So we just splat out the first instruction. Long term, we
     // need something cleaner. But this works on arm64 for now.
 
-    CCallHelpers::emitJITCodeOver(fastPathStart(), [&] (CCallHelpers& jit) {
-        if (isDataIC())
-            emitFirstInstructionForDataIC(jit, u.dataIC.m_callLinkInfoGPR);
-        else {
-            CCallHelpers::revertJumpReplacementToBranchPtrWithPatch(
-                CCallHelpers::startOfBranchPtrWithPatchOnRegister(u.codeIC.m_calleeLocation), calleeGPR(), nullptr);
-        }
-    },  "Resetting PolymorphicCall stubbed CallLinkInfo");
+    if (isDataIC()) {
+        m_calleeOrCodeBlock.clear();
+        u.dataIC.m_monomorphicCallDestination = nullptr;
+    } else {
+        CCallHelpers::revertJumpReplacementToBranchPtrWithPatch(
+            CCallHelpers::startOfBranchPtrWithPatchOnRegister(u.codeIC.m_calleeLocation), calleeGPR(), nullptr);
+    }
 }
 
 void CallLinkInfo::setStub(Ref<PolymorphicCallStubRoutine>&& newStub)
@@ -479,13 +476,11 @@
     clearStub();
     m_stub = WTFMove(newStub);
 
+    m_calleeOrCodeBlock.clear();
+
     if (isDataIC()) {
-        CCallHelpers::emitJITCodeOver(fastPathStart(), [&] (CCallHelpers& jit) {
-            auto jump = jit.jump();
-            jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-                linkBuffer.link(jump, CodeLocationLabel<JITStubRoutinePtrTag>(m_stub->code().code()));
-            });
-        }, "Patching call to PolymorphicCallStubRoutine in CallLinkInfo");
+        *bitwise_cast<uintptr_t*>(m_calleeOrCodeBlock.slot()) = polymorphicCalleeMask;
+        u.dataIC.m_monomorphicCallDestination = m_stub->code().code().retagged<JSEntryPtrTag>();
     } else {
         MacroAssembler::replaceWithJump(
             MacroAssembler::startOfBranchPtrWithPatchOnRegister(u.codeIC.m_calleeLocation),

Modified: trunk/Source/_javascript_Core/bytecode/CallLinkInfo.h (277837 => 277838)


--- trunk/Source/_javascript_Core/bytecode/CallLinkInfo.h	2021-05-20 23:39:30 UTC (rev 277837)
+++ trunk/Source/_javascript_Core/bytecode/CallLinkInfo.h	2021-05-21 00:14:50 UTC (rev 277838)
@@ -173,7 +173,6 @@
     };
 
 private:
-    void emitFirstInstructionForDataIC(CCallHelpers&, GPRReg callLinkInfoGPR);
     MacroAssembler::JumpList emitFastPathImpl(CCallHelpers&, GPRReg calleeGPR, GPRReg callLinkInfoGPR, UseDataIC, WTF::Function<void()> prepareForTailCall) WARN_UNUSED_RETURN;
 public:
     MacroAssembler::JumpList emitFastPath(CCallHelpers&, GPRReg calleeGPR, GPRReg callLinkInfoGPR, UseDataIC) WARN_UNUSED_RETURN;

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (277837 => 277838)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2021-05-20 23:39:30 UTC (rev 277837)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2021-05-21 00:14:50 UTC (rev 277838)
@@ -1456,6 +1456,7 @@
     
     GPRReg calleeGPR = callLinkInfo.calleeGPR();
 
+    bool isDataIC = callLinkInfo.isDataIC();
     CCallHelpers stubJit(callerCodeBlock);
 
     std::unique_ptr<CallFrameShuffler> frameShuffler;
@@ -1538,6 +1539,8 @@
                 CCallHelpers::TrustedImm32(1),
                 CCallHelpers::Address(fastCountsBaseGPR, caseIndex * sizeof(uint32_t)));
         }
+
+        bool needsDoneJump = false;
         if (frameShuffler) {
             CallFrameShuffler(stubJit, frameShuffler->snapshot()).prepareForTailCall();
             calls[caseIndex].call = stubJit.nearTailCall();
@@ -1544,10 +1547,17 @@
         } else if (callLinkInfo.isTailCall()) {
             stubJit.prepareForTailCallSlow();
             calls[caseIndex].call = stubJit.nearTailCall();
-        } else
-            calls[caseIndex].call = stubJit.nearCall();
+        } else {
+            if (isDataIC)
+                calls[caseIndex].call = stubJit.nearTailCall();
+            else {
+                calls[caseIndex].call = stubJit.nearCall();
+                needsDoneJump = true;
+            }
+        }
         calls[caseIndex].codePtr = codePtr;
-        done.append(stubJit.jump());
+        if (needsDoneJump)
+            done.append(stubJit.jump());
     }
     
     slowPath.link(&stubJit);
@@ -1571,6 +1581,12 @@
     }
     stubJit.move(CCallHelpers::TrustedImmPtr(globalObject), GPRInfo::regT3);
     stubJit.move(CCallHelpers::TrustedImmPtr(&callLinkInfo), GPRInfo::regT2);
+    if (isDataIC && !callLinkInfo.isTailCall()) {
+        // We were called from the fast path, get rid of any remnants of that
+        // which may exist. This really only matters for x86, which adjusts
+        // SP for calls.
+        stubJit.preserveReturnAddressAfterCall(GPRInfo::regT4);
+    }
     stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.doneLocation().untaggedExecutableAddress()), GPRInfo::regT4);
     
     stubJit.restoreReturnAddressBeforeReturn(GPRInfo::regT4);
@@ -1594,7 +1610,9 @@
         patchBuffer.link(callToCodePtr.call, FunctionPtr<JSEntryPtrTag>(callToCodePtr.codePtr));
 #endif
     }
-    patchBuffer.link(done, callLinkInfo.doneLocation());
+
+    if (!done.empty())
+        patchBuffer.link(done, callLinkInfo.doneLocation());
     patchBuffer.link(slow, CodeLocationLabel<JITThunkPtrTag>(vm.getCTIStub(linkPolymorphicCallThunkGenerator).code()));
     
     auto stubRoutine = adoptRef(*new PolymorphicCallStubRoutine(
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to