⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 293154 in webkit


Ignore:
Timestamp:
Apr 21, 2022, 2:51:18 AM (4 years ago)
Author:
Carlos Garcia Campos
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):

Location:
releases/WebKitGTK/webkit-2.36/Source/JavaScriptCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • releases/WebKitGTK/webkit-2.36/Source/JavaScriptCore/ChangeLog

    r293153 r293154  
     12022-03-24  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] JSRemoteFunction thunk should materialize code-pointer
     4        https://bugs.webkit.org/show_bug.cgi?id=238313
     5
     6        Reviewed by Mark Lam.
     7
     8        When invoking a JSRemoteFunction, we must first wrap the arguments passed to it.
     9        The wrapping operation may trigger a GC, and GC can jettison JIT code. As a result,
     10        even though we know that the target JSFunction has JIT code that we want to execute,
     11        the JIT code may be jettisoned (while wrapping the arguments for it) before we get
     12        to the call. This resulted in occasional crashes on the JSTests/stress/shadow-realm-evaluate.js test.
     13
     14        This patch fixes this by doing a null check on the JIT code just before calling it,
     15        and if null (i.e. the JIT code has been jettisoned), re-materializing the JIT code
     16        first before making the call.
     17
     18        * jit/JITOperations.cpp:
     19        (JSC::JSC_DEFINE_JIT_OPERATION):
     20        * jit/JITOperations.h:
     21        * jit/ThunkGenerators.cpp:
     22        (JSC::remoteFunctionCallGenerator):
     23
    1242022-03-23  Geza Lore  <glore@igalia.com>
    225
  • releases/WebKitGTK/webkit-2.36/Source/JavaScriptCore/jit/JITOperations.cpp

    r289417 r293154  
    159159
    160160    RELEASE_AND_RETURN(scope, JSValue::encode(getWrappedValue(globalObject, globalObject, JSValue::decode(encodedValue))));
     161}
     162
     163JSC_DEFINE_JIT_OPERATION(operationMaterializeRemoteFunctionTargetCode, void*, (JSRemoteFunction* callee))
     164{
     165    JSGlobalObject* globalObject = callee->globalObject();
     166    VM& vm = globalObject->vm();
     167
     168    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
     169    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
     170    auto throwScope = DECLARE_THROW_SCOPE(vm);
     171
     172    ASSERT(isRemoteFunction(vm, callee));
     173
     174    auto* targetFunction = jsCast<JSFunction*>(callee->targetFunction()); // We call this function only when JSRemoteFunction's target is JSFunction.
     175    ExecutableBase* executable = targetFunction->executable();
     176
     177    // Force the executable to cache its arity entrypoint.
     178    {
     179        DeferTraps deferTraps(vm); // We can't jettison any code until after we link the call.
     180        if (!executable->isHostFunction()) {
     181            JSScope* scope = targetFunction->scopeUnchecked();
     182            FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
     183            CodeBlock* codeBlockSlot = nullptr;
     184            functionExecutable->prepareForExecution<FunctionExecutable>(vm, targetFunction, scope, CodeForCall, codeBlockSlot);
     185            RETURN_IF_EXCEPTION(throwScope, nullptr);
     186        }
     187        return executable->entrypointFor(CodeForCall, MustCheckArity).executableAddress();
     188    }
    161189}
    162190
  • releases/WebKitGTK/webkit-2.36/Source/JavaScriptCore/jit/JITOperations.h

    r289417 r293154  
    159159JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForCaller, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
    160160JSC_DECLARE_JIT_OPERATION(operationGetWrappedValueForTarget, EncodedJSValue, (JSRemoteFunction*, EncodedJSValue));
     161JSC_DECLARE_JIT_OPERATION(operationMaterializeRemoteFunctionTargetCode, void*, (JSRemoteFunction*));
    161162JSC_DECLARE_JIT_OPERATION(operationThrowRemoteFunctionException, EncodedJSValue, (JSRemoteFunction*));
    162163
  • releases/WebKitGTK/webkit-2.36/Source/JavaScriptCore/jit/ThunkGenerators.cpp

    r293153 r293154  
    15281528        jit.storePtr(GPRInfo::regT1, jit.addressFor(loopIndex));
    15291529
     1530        jit.setupArguments<decltype(operationGetWrappedValueForTarget)>(GPRInfo::regT0, valueRegs);
    15301531        jit.prepareCallOperation(vm);
    1531         jit.setupArguments<decltype(operationGetWrappedValueForTarget)>(GPRInfo::regT0, valueRegs);
    15321532        jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForTarget)), GPRInfo::nonArgGPR0);
    15331533        emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
     
    15501550    jit.storeCell(GPRInfo::regT2, CCallHelpers::calleeFrameSlot(CallFrameSlot::callee));
    15511551
    1552     jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT0);
    1553     auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
    1554     jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT0);
     1552    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT2, JSFunction::offsetOfExecutableOrRareData()), GPRInfo::regT1);
     1553    auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT1, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
     1554    jit.loadPtr(CCallHelpers::Address(GPRInfo::regT1, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), GPRInfo::regT1);
    15551555    hasExecutable.link(&jit);
    15561556
    15571557    jit.loadPtr(
    15581558        CCallHelpers::Address(
    1559             GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
    1560         GPRInfo::regT0);
    1561 
     1559            GPRInfo::regT1, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
     1560        GPRInfo::regT1);
     1561    auto codeExists = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT1);
     1562
     1563    // The calls to operationGetWrappedValueForTarget above may GC, and any GC can potentially jettison the JIT code in the target JSFunction.
     1564    // 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
     1565    // that operationMaterializeRemoteFunctionTargetCode should be able to re-materialize the JIT code (except for any OOME) because we only
     1566    // 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.
     1567    jit.setupArguments<decltype(operationMaterializeRemoteFunctionTargetCode)>(GPRInfo::regT0);
     1568    jit.prepareCallOperation(vm);
     1569    jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationMaterializeRemoteFunctionTargetCode)), GPRInfo::nonArgGPR0);
     1570    emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
     1571    jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
     1572    exceptionChecks.append(jit.emitJumpIfException(vm));
     1573    jit.move(GPRInfo::returnValueGPR, GPRInfo::regT1);
     1574
     1575    codeExists.link(&jit);
    15621576    // Based on the check above, we should be good with this. On ARM64, emitPointerValidation will do this.
    15631577#if ASSERT_ENABLED && !CPU(ARM64E)
    15641578    {
    1565         CCallHelpers::Jump checkNotNull = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT0);
     1579        CCallHelpers::Jump checkNotNull = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT1);
    15661580        jit.abortWithReason(TGInvalidPointer);
    15671581        checkNotNull.link(&jit);
     
    15691583#endif
    15701584
    1571     emitPointerValidation(jit, GPRInfo::regT0, JSEntryPtrTag);
    1572     jit.call(GPRInfo::regT0, JSEntryPtrTag);
     1585    emitPointerValidation(jit, GPRInfo::regT1, JSEntryPtrTag);
     1586    jit.call(GPRInfo::regT1, JSEntryPtrTag);
    15731587
    15741588    // Wrap return value
     
    15831597    resultIsPrimitive.append(jit.branchIfNotObject(resultRegs.payloadGPR()));
    15841598
    1585     jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForCaller)), GPRInfo::nonArgGPR0);
    1586     emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
    1587 
    15881599    jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT2);
    15891600    jit.setupArguments<decltype(operationGetWrappedValueForCaller)>(GPRInfo::regT2, resultRegs);
    15901601    jit.prepareCallOperation(vm);
     1602    jit.move(CCallHelpers::TrustedImmPtr(tagCFunction<OperationPtrTag>(operationGetWrappedValueForCaller)), GPRInfo::nonArgGPR0);
     1603    emitPointerValidation(jit, GPRInfo::nonArgGPR0, OperationPtrTag);
    15911604    jit.call(GPRInfo::nonArgGPR0, OperationPtrTag);
    15921605    exceptionChecks.append(jit.emitJumpIfException(vm));
Note: See TracChangeset for help on using the changeset viewer.