Ignore:
Timestamp:
May 16, 2018, 12:05:27 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Check TypeInfo first before calling getCallData when we would like to check whether given object is a function
https://bugs.webkit.org/show_bug.cgi?id=185601

Reviewed by Saam Barati.

Source/JavaScriptCore:

Rename TypeOfShouldCallGetCallData to OverridesGetCallData. And check OverridesGetCallData
before calling getCallData when we would like to check whether a given object is callable
since getCallData is a virtual call. When we call the object anyway, directly calling getCallData
is fine. But if we would like to check whether the object is callable, we can have non
callable objects frequently. In that case, we should not call getCallData if we can avoid it.

To do this cleanly, we refactor JSValue::{isFunction,isCallable}. We add JSCell::{isFunction,isCallable}
and JSValue ones call into these functions. Inside JSCell::{isFunction,isCallable}, we perform
OverridesGetCallData checking before calling getCallData.

We found that this virtual call exists in JSON.stringify's critial path. Checking
OverridesGetCallData improves Kraken/json-stringify-tinderbox by 2-4%.

baseline patched

json-stringify-tinderbox 38.807+-0.350 37.216+-0.337 definitely 1.0427x faster

In addition to that, we also add OverridesGetCallData flag to JSFunction while we keep JSFunctionType checking fast path
since major cases are covered by this fast JSFunctionType checking.

  • API/JSCallbackObject.h:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileIsObjectOrNull):
(JSC::DFG::SpeculativeJIT::compileIsFunction):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::isExoticForTypeof):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::emitTypeOf):

  • runtime/ExceptionHelpers.cpp:

(JSC::createError):
(JSC::createInvalidFunctionApplyParameterError):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncToString):

  • runtime/InternalFunction.h:
  • runtime/JSCJSValue.h:
  • runtime/JSCJSValueInlines.h:

(JSC::JSValue::isFunction const):
(JSC::JSValue::isCallable const):

  • runtime/JSCell.h:
  • runtime/JSCellInlines.h:

(JSC::JSCell::isFunction):
ALWAYS_INLINE works well for my environment.
(JSC::JSCell::isCallable):

  • runtime/JSFunction.h:
  • runtime/JSONObject.cpp:

(JSC::Stringifier::toJSON):
(JSC::Stringifier::toJSONImpl):
(JSC::Stringifier::appendStringifiedValue):

  • runtime/JSObjectInlines.h:

(JSC::createListFromArrayLike):

  • runtime/JSTypeInfo.h:

(JSC::TypeInfo::overridesGetCallData const):
(JSC::TypeInfo::typeOfShouldCallGetCallData const): Deleted.

  • runtime/Operations.cpp:

(JSC::jsTypeStringForValue):
(JSC::jsIsObjectTypeOrNull):

  • runtime/ProxyObject.h:
  • runtime/RuntimeType.cpp:

(JSC::runtimeTypeForValue):

  • runtime/RuntimeType.h:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):

  • runtime/TypeProfilerLog.cpp:

(JSC::TypeProfilerLog::TypeProfilerLog):
(JSC::TypeProfilerLog::processLogEntries):

  • runtime/TypeProfilerLog.h:
  • runtime/VM.cpp:

(JSC::VM::enableTypeProfiler):

  • tools/JSDollarVM.cpp:

(JSC::functionFindTypeForExpression):
(JSC::functionReturnTypeFor):
(JSC::functionHasBasicBlockExecuted):
(JSC::functionBasicBlockExecutionCount):

  • wasm/js/JSWebAssemblyHelpers.h:

(JSC::getWasmBufferFromValue):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::create):

  • wasm/js/WebAssemblyFunction.cpp:

(JSC::callWebAssemblyFunction):

  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):

  • wasm/js/WebAssemblyPrototype.cpp:

(JSC::webAssemblyInstantiateFunc):
(JSC::webAssemblyInstantiateStreamingInternal):

  • wasm/js/WebAssemblyWrapperFunction.cpp:

(JSC::WebAssemblyWrapperFunction::finishCreation):

Source/WebCore:

No behavior change.

  • Modules/plugins/QuickTimePluginReplacement.mm:

(WebCore::QuickTimePluginReplacement::ensureReplacementScriptInjected):

  • bindings/js/JSCustomElementRegistryCustom.cpp:

(WebCore::getCustomElementCallback):

  • bindings/js/JSDOMConstructorBase.h:
  • bindings/js/JSDOMConvertCallbacks.h:

(WebCore::Converter<IDLCallbackFunction<T>>::convert):

  • bindings/js/JSDOMPromise.cpp:

(WebCore::DOMPromise::whenSettled):

  • bindings/js/ReadableStream.cpp:

(WebCore::ReadableStream::pipeTo):
(WebCore::ReadableStream::tee):

  • bindings/js/ReadableStreamDefaultController.cpp:

(WebCore::ReadableStreamDefaultController::invoke):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):
(GenerateOverloadDispatcher):

  • bindings/scripts/test/JS/JSTestObj.h:
  • bindings/scripts/test/JS/JSTestPluginInterface.h:
  • bridge/objc/objc_runtime.h:
  • bridge/runtime_method.h:
  • bridge/runtime_object.h:
  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::ensureMediaControlsInjectedScript):

  • testing/Internals.cpp:

(WebCore::Internals::parserMetaData):
(WebCore::Internals::cloneArrayBuffer):

Source/WebKit:

  • WebProcess/Plugins/Netscape/JSNPObject.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r231310 r231839  
    112112
    113113    JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
    114     JSValue toJSONImpl(JSValue value, JSValue toJSONFunction, const PropertyNameForFunctionCall&);
     114    JSValue toJSONImpl(VM&, JSValue, JSValue toJSONFunction, const PropertyNameForFunctionCall&);
    115115
    116116    enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedOrSymbolValue };
     
    300300    RETURN_IF_EXCEPTION(scope, { });
    301301    scope.release();
    302     return toJSONImpl(value, toJSONFunction, propertyName);
    303 }
    304 
    305 JSValue Stringifier::toJSONImpl(JSValue value, JSValue toJSONFunction, const PropertyNameForFunctionCall& propertyName)
     302    return toJSONImpl(vm, value, toJSONFunction, propertyName);
     303}
     304
     305JSValue Stringifier::toJSONImpl(VM& vm, JSValue value, JSValue toJSONFunction, const PropertyNameForFunctionCall& propertyName)
    306306{
    307307    CallType callType;
    308308    CallData callData;
    309     if (!toJSONFunction.isCallable(callType, callData))
     309    if (!toJSONFunction.isCallable(vm, callType, callData))
    310310        return value;
    311311
     
    381381
    382382    JSObject* object = asObject(value);
    383 
    384     CallData callData;
    385     if (object->methodTable(vm)->getCallData(object, callData) != CallType::None) {
     383    if (object->isFunction(vm)) {
    386384        if (holder.isArray()) {
    387385            builder.appendLiteral("null");
Note: See TracChangeset for help on using the changeset viewer.