Title: [293154] releases/WebKitGTK/webkit-2.36/Source/_javascript_Core
Revision
293154
Author
carlo...@webkit.org
Date
2022-04-21 02:51:18 -0700 (Thu, 21 Apr 2022)

Log Message

Merge r291815 - [JSC] JSRemoteFunction thunk should materialize code-pointer
https://bugs.webkit.org/show_bug.cgi?id=238313

Reviewed by Mark Lam.

When invoking a JSRemoteFunction, we must first wrap the arguments passed to it.
The wrapping operation may trigger a GC, and GC can jettison JIT code. As a result,
even though we know that the target JSFunction has JIT code that we want to execute,
the JIT code may be jettisoned (while wrapping the arguments for it) before we get
to the call. This resulted in occasional crashes on the JSTests/stress/shadow-realm-evaluate.js test.

This patch fixes this by doing a null check on the JIT code just before calling it,
and if null (i.e. the JIT code has been jettisoned), re-materializing the JIT code
first before making the call.

* jit/JITOperations.cpp:
(JSC::JSC_DEFINE_JIT_OPERATION):
* jit/JITOperations.h:
* jit/ThunkGenerators.cpp:
(JSC::remoteFunctionCallGenerator):

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/ChangeLog (293153 => 293154)


--- releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/ChangeLog	2022-04-21 09:51:14 UTC (rev 293153)
+++ releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/ChangeLog	2022-04-21 09:51:18 UTC (rev 293154)
@@ -1,3 +1,26 @@
+2022-03-24  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] JSRemoteFunction thunk should materialize code-pointer
+        https://bugs.webkit.org/show_bug.cgi?id=238313
+
+        Reviewed by Mark Lam.
+
+        When invoking a JSRemoteFunction, we must first wrap the arguments passed to it.
+        The wrapping operation may trigger a GC, and GC can jettison JIT code. As a result,
+        even though we know that the target JSFunction has JIT code that we want to execute,
+        the JIT code may be jettisoned (while wrapping the arguments for it) before we get
+        to the call. This resulted in occasional crashes on the JSTests/stress/shadow-realm-evaluate.js test.
+
+        This patch fixes this by doing a null check on the JIT code just before calling it,
+        and if null (i.e. the JIT code has been jettisoned), re-materializing the JIT code
+        first before making the call.
+
+        * jit/JITOperations.cpp:
+        (JSC::JSC_DEFINE_JIT_OPERATION):
+        * jit/JITOperations.h:
+        * jit/ThunkGenerators.cpp:
+        (JSC::remoteFunctionCallGenerator):
+
 2022-03-23  Geza Lore  <gl...@igalia.com>
 
         [JSC] Fix remoteFunctionCallGenerator on MIPS

Modified: releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.cpp (293153 => 293154)


--- releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.cpp	2022-04-21 09:51:14 UTC (rev 293153)
+++ releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.cpp	2022-04-21 09:51:18 UTC (rev 293154)
@@ -160,6 +160,34 @@
     RELEASE_AND_RETURN(scope, JSValue::encode(getWrappedValue(globalObject, globalObject, JSValue::decode(encodedValue))));
 }
 
+JSC_DEFINE_JIT_OPERATION(operationMaterializeRemoteFunctionTargetCode, void*, (JSRemoteFunction* callee))
+{
+    JSGlobalObject* globalObject = callee->globalObject();
+    VM& vm = globalObject->vm();
+
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    ASSERT(isRemoteFunction(vm, callee));
+
+    auto* targetFunction = jsCast<JSFunction*>(callee->targetFunction()); // We call this function only when JSRemoteFunction's target is JSFunction.
+    ExecutableBase* executable = targetFunction->executable();
+
+    // Force the executable to cache its arity entrypoint.
+    {
+        DeferTraps deferTraps(vm); // We can't jettison any code until after we link the call.
+        if (!executable->isHostFunction()) {
+            JSScope* scope = targetFunction->scopeUnchecked();
+            FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
+            CodeBlock* codeBlockSlot = nullptr;
+            functionExecutable->prepareForExecution<FunctionExecutable>(vm, targetFunction, scope, CodeForCall, codeBlockSlot);
+            RETURN_IF_EXCEPTION(throwScope, nullptr);
+        }
+        return executable->entrypointFor(CodeForCall, MustCheckArity).executableAddress();
+    }
+}
+
 JSC_DEFINE_JIT_OPERATION(operationThrowRemoteFunctionException, EncodedJSValue, (JSRemoteFunction* callee))
 {
     JSGlobalObject* globalObject = callee->globalObject();

Modified: releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.h (293153 => 293154)


--- releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.h	2022-04-21 09:51:14 UTC (rev 293153)
+++ releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/JITOperations.h	2022-04-21 09:51:18 UTC (rev 293154)
@@ -158,6 +158,7 @@
 JSC_DECLARE_JIT_OPERATION(operationThrowIteratorResultIsNotObject, void, (JSGlobalObject*));
 JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForCaller, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
 JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForTarget, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
+JSC_DECLARE_JIT_OPERATION(operationMaterializeRemoteFunctionTargetCode, void*, (JSRemoteFunction*));
 JSC_DECLARE_JIT_OPERATION(operationThrowRemoteFunctionException, EncodedJSValue, (JSRemoteFunction*));
 
 JSC_DECLARE_JIT_OPERATION(operationThrowStackOverflowError, void, (CodeBlock*));

Modified: releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/ThunkGenerators.cpp (293153 => 293154)


--- releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/ThunkGenerators.cpp	2022-04-21 09:51:14 UTC (rev 293153)
+++ releases/WebKitGTK/webkit-2.36/Source/_javascript_Core/jit/ThunkGenerators.cpp	2022-04-21 09:51:18 UTC (rev 293154)
@@ -1527,8 +1527,8 @@
 
         jit.storePtr(GPRInfo::regT1, jit.addressFor(loopIndex));
 
+        jit.setupArguments<decltype(operationGetWrappedValueForTarget)>(GPRInfo::regT0, valueRegs);
         jit.prepareCallOperation(vm);
-        jit.setupArguments<decltype(operationGetWrappedValueForTarget)>(GPRInfo::regT0, valueRegs);
         jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForTarget)), GPRInfo::nonArgGPR0);
         emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
         jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
@@ -1549,27 +1549,41 @@
     jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, JSRemoteFunction::offsetOfTargetFunction()), GPRInfo::regT2);
     jit.storeCell(GPRInfo::regT2, CCallHelpers::calleeFrameSlot(CallFrameSlot::callee));
 
-    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT0);
-    auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
-    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT0);
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT1);
+    auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT1, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT1, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT1);
     hasExecutable.link(&jit);
 
     jit.loadPtr(
         CCallHelpers::Address(
-            GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
-        GPRInfo::regT0);
+            GPRInfo::regT1, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
+        GPRInfo::regT1);
+    auto codeExists = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT1);
 
+    // The calls to operationGetWrappedValueForTarget above may GC, and any GC can potentially jettison the JIT code in the target JSFunction.
+    // If we find that the JIT code is null (i.e. has been jettisoned), then we need to re-materialize it for the call below. Note that we know
+    // that operationMaterializeRemoteFunctionTargetCode should be able to re-materialize the JIT code (except for any OOME) because we only
+    // went down this code path after we found a non-null JIT code (in the noCode check) above i.e. it should be possible to materialize the JIT code.
+    jit.setupArguments<decltype(operationMaterializeRemoteFunctionTargetCode)>(GPRInfo::regT0);
+    jit.prepareCallOperation(vm);
+    jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationMaterializeRemoteFunctionTargetCode)), GPRInfo::nonArgGPR0);
+    emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
+    jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
+    exceptionChecks.append(jit.emitJumpIfException(vm));
+    jit.move(GPRInfo::returnValueGPR, GPRInfo::regT1);
+
+    codeExists.link(&jit);
     // Based on the check above, we should be good with this. On ARM64, emitPointerValidation will do this.
 #if ASSERT_ENABLED && !CPU(ARM64E)
     {
-        CCallHelpers::Jump checkNotNull = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT0);
+        CCallHelpers::Jump checkNotNull = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT1);
         jit.abortWithReason(TGInvalidPointer);
         checkNotNull.link(&jit);
     }
 #endif
 
-    emitPointerValidation(jit, GPRInfo::regT0, JSEntryPtrTag);
-    jit.call(GPRInfo::regT0, JSEntryPtrTag);
+    emitPointerValidation(jit, GPRInfo::regT1, JSEntryPtrTag);
+    jit.call(GPRInfo::regT1, JSEntryPtrTag);
 
     // Wrap return value
 #if USE(JSVALUE64)
@@ -1582,12 +1596,11 @@
     resultIsPrimitive.append(jit.branchIfNotCell(resultRegs));
     resultIsPrimitive.append(jit.branchIfNotObject(resultRegs.payloadGPR()));
 
-    jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForCaller)), GPRInfo::nonArgGPR0);
-    emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
-
     jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT2);
     jit.setupArguments<decltype(operationGetWrappedValueForCaller)>(GPRInfo::regT2, resultRegs);
     jit.prepareCallOperation(vm);
+    jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForCaller)), GPRInfo::nonArgGPR0);
+    emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
     jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
     exceptionChecks.append(jit.emitJumpIfException(vm));
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to