Ignore:
Timestamp:
Nov 2, 2016, 8:20:53 PM (9 years ago)
Author:
Yusuke Suzuki
Message:

[DOMJIT] Add DOMJIT::Signature
https://bugs.webkit.org/show_bug.cgi?id=162980

Reviewed by Saam Barati and Sam Weinig.

Source/JavaScriptCore:

This patch introduces a new mechanism called DOMJIT::Signature. We can annotate the function with DOMJIT::Signature.
DOMJIT::Signature has type information of that function. And it also maintains the effect of the function and the
pointer to the unsafe function. The unsafe function means the function without type and argument count checks.
By using these information, we can separate type and argument count checks from the function. And we can emit
these things as DFG checks and convert the function call itself to CallDOM node. CallDOM node can call the unsafe
function directly without any checks. Furthermore, this CallDOM node can represent its own clobberizing rules based
on DOMJIT::Effect maintained by DOMJIT::Signature. It allows us to make opaque Call node to a CallDOM node that
merely reads some part of heap. These changes (1) can drop duplicate type checks in DFG, (2) offer ability to move
CallDOM node to somewhere, and (3) track more detailed heap reads and writes of CallDOM nodes.

We first emit Call node with DOMJIT::Signature in DFGByteCodeParser. And in the fixup phase, we attempt to lower
Call node to CallDOM node with checks & edge filters. This is because we do not know the type predictions in
DFGByteCodeParser phase. If we always emit CallDOM node in DFGByteCodeParser, if we evaluate div.getAttribute(true)
thingy, the Uncountable OSR exits repeatedly happen because AI figures out the abstract value is cleared.

Currently, DOMJIT signature only allows the types that can reside in GPR. This is because the types of the unsafe
function arguments are represented as the sequence of void*. In the future, we will extend to accept other types like
float, double etc.

We annotate several functions in Element. In particular, we annotate Element::getAttribute. This allows us to perform
LICM in Dromaeo dom-attr test. In the Dromaeo dom-attr getAttribute test, we can see 32x improvement. (134974.8 v.s. 4203.4)

(JSC::CallVariant::functionExecutable):
(JSC::CallVariant::nativeExecutable):
(JSC::CallVariant::signatureFor):

  • bytecode/SpeculatedType.h:

(JSC::isNotStringSpeculation):
(JSC::isNotInt32Speculation):
(JSC::isNotBooleanSpeculation):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleDOMJITCall):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::attemptToMakeCallDOM):
(JSC::DFG::FixupPhase::fixupCheckDOM):
(JSC::DFG::FixupPhase::fixupCallDOM):

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::convertToCallDOM):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::shouldSpeculateNotInt32):
(JSC::DFG::Node::shouldSpeculateNotBoolean):
(JSC::DFG::Node::shouldSpeculateNotString):
(JSC::DFG::Node::hasSignature):
(JSC::DFG::Node::signature):

  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileCallDOM):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • domjit/DOMJITEffect.h:

(JSC::DOMJIT::Effect::Effect):
(JSC::DOMJIT::Effect::forWrite):
(JSC::DOMJIT::Effect::forRead):
(JSC::DOMJIT::Effect::forReadWrite):
(JSC::DOMJIT::Effect::forPure):
(JSC::DOMJIT::Effect::forDef):
(JSC::DOMJIT::Effect::mustGenerate):
In clang, we cannot make this Effect constructor constexpr if we use Optional<HeapRange>.
So we use HeapRange::top() for Nullopt def now.

  • domjit/DOMJITHeapRange.h:

(JSC::DOMJIT::HeapRange::fromRaw):
(JSC::DOMJIT::HeapRange::operator bool):
(JSC::DOMJIT::HeapRange::operator==):
(JSC::DOMJIT::HeapRange::operator!=):
(JSC::DOMJIT::HeapRange::fromConstant):

  • domjit/DOMJITSignature.h: Copied from Source/JavaScriptCore/domjit/DOMJITEffect.h.

(JSC::DOMJIT::Signature::Signature):
(JSC::DOMJIT::Signature::argumentCount):
(JSC::DOMJIT::Signature::checkDOM):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):

  • jit/JITOperations.h:
  • jit/JITThunks.cpp:

(JSC::JITThunks::hostFunctionStub):

  • jit/JITThunks.h:
  • runtime/JSBoundFunction.cpp:

(JSC::JSBoundFunction::create):

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

(JSC::JSFunction::create):

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

(JSC::JSNativeStdFunction::create):

  • runtime/JSObject.cpp:

(JSC::JSObject::putDirectNativeFunction):

  • runtime/JSObject.h:
  • runtime/Lookup.h:

(JSC::HashTableValue::functionLength):
(JSC::HashTableValue::signature):
(JSC::reifyStaticProperty):

  • runtime/NativeExecutable.cpp:

(JSC::NativeExecutable::create):
(JSC::NativeExecutable::NativeExecutable):

  • runtime/NativeExecutable.h:
  • runtime/PropertySlot.h:
  • runtime/VM.cpp:

(JSC::VM::getHostFunction):

  • runtime/VM.h:

Source/WebCore:

We introduce DOMJIT::Signature. This signature object is automatically generated by IDL code generator.
It holds (1) types, (2) pointer to the unsafe function (the function without checks), and (3) the effect
of the function. We use constexpr to initialize DOMJIT::Signature without invoking global constructors.
Thus the content is embedded into the binary as the constant values.

We also clean up the IDL code generator related to DOMJIT part. Instead of switching things inside IDL
code generator, we use C++ template to dispatch things at compile time. This template meta programming
is highly utilized in IDL these days.

To make DOMJIT::Signature constexpr, we also need to define DOMJIT abstract heap things in the build time.
To do so, we introduce a tiny Ruby script to calculate the range of abstract heaps. We can offer the abstract
heap tree as YAML format and the script will produce a C++ header holding the calculated abstract heap ranges

  • CMakeLists.txt:
  • DerivedSources.make:
  • ForwardingHeaders/bytecode/SpeculatedType.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.h.
  • ForwardingHeaders/domjit/DOMJITSignature.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp.
  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/JSDOMGlobalObject.h:
  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):
(GeneratePropertiesHashTable):
(GetUnsafeArgumentType):
(GetArgumentTypeFilter):
(GetResultTypeFilter):
(GenerateImplementation):
(UnsafeToNative):
(GenerateHashTableValueArray):
(ComputeFunctionSpecial):

  • bindings/scripts/IDLAttributes.txt:
  • bindings/scripts/test/JS/JSTestDOMJIT.cpp:

(WebCore::BindingCaller<JSTestDOMJIT>::castForOperation):
(WebCore::TestDOMJITAnyAttrDOMJIT::TestDOMJITAnyAttrDOMJIT):
(WebCore::TestDOMJITBooleanAttrDOMJIT::TestDOMJITBooleanAttrDOMJIT):
(WebCore::TestDOMJITByteAttrDOMJIT::TestDOMJITByteAttrDOMJIT):
(WebCore::TestDOMJITOctetAttrDOMJIT::TestDOMJITOctetAttrDOMJIT):
(WebCore::TestDOMJITShortAttrDOMJIT::TestDOMJITShortAttrDOMJIT):
(WebCore::TestDOMJITUnsignedShortAttrDOMJIT::TestDOMJITUnsignedShortAttrDOMJIT):
(WebCore::TestDOMJITLongAttrDOMJIT::TestDOMJITLongAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongAttrDOMJIT::TestDOMJITUnsignedLongAttrDOMJIT):
(WebCore::TestDOMJITLongLongAttrDOMJIT::TestDOMJITLongLongAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongLongAttrDOMJIT::TestDOMJITUnsignedLongLongAttrDOMJIT):
(WebCore::TestDOMJITFloatAttrDOMJIT::TestDOMJITFloatAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedFloatAttrDOMJIT::TestDOMJITUnrestrictedFloatAttrDOMJIT):
(WebCore::TestDOMJITDoubleAttrDOMJIT::TestDOMJITDoubleAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedDoubleAttrDOMJIT::TestDOMJITUnrestrictedDoubleAttrDOMJIT):
(WebCore::TestDOMJITDomStringAttrDOMJIT::TestDOMJITDomStringAttrDOMJIT):
(WebCore::TestDOMJITByteStringAttrDOMJIT::TestDOMJITByteStringAttrDOMJIT):
(WebCore::TestDOMJITUsvStringAttrDOMJIT::TestDOMJITUsvStringAttrDOMJIT):
(WebCore::TestDOMJITNodeAttrDOMJIT::TestDOMJITNodeAttrDOMJIT):
(WebCore::TestDOMJITBooleanNullableAttrDOMJIT::TestDOMJITBooleanNullableAttrDOMJIT):
(WebCore::TestDOMJITByteNullableAttrDOMJIT::TestDOMJITByteNullableAttrDOMJIT):
(WebCore::TestDOMJITOctetNullableAttrDOMJIT::TestDOMJITOctetNullableAttrDOMJIT):
(WebCore::TestDOMJITShortNullableAttrDOMJIT::TestDOMJITShortNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedShortNullableAttrDOMJIT::TestDOMJITUnsignedShortNullableAttrDOMJIT):
(WebCore::TestDOMJITLongNullableAttrDOMJIT::TestDOMJITLongNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongNullableAttrDOMJIT::TestDOMJITUnsignedLongNullableAttrDOMJIT):
(WebCore::TestDOMJITLongLongNullableAttrDOMJIT::TestDOMJITLongLongNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongLongNullableAttrDOMJIT::TestDOMJITUnsignedLongLongNullableAttrDOMJIT):
(WebCore::TestDOMJITFloatNullableAttrDOMJIT::TestDOMJITFloatNullableAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT):
(WebCore::TestDOMJITDoubleNullableAttrDOMJIT::TestDOMJITDoubleNullableAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT):
(WebCore::TestDOMJITDomStringNullableAttrDOMJIT::TestDOMJITDomStringNullableAttrDOMJIT):
(WebCore::TestDOMJITByteStringNullableAttrDOMJIT::TestDOMJITByteStringNullableAttrDOMJIT):
(WebCore::TestDOMJITUsvStringNullableAttrDOMJIT::TestDOMJITUsvStringNullableAttrDOMJIT):
(WebCore::TestDOMJITNodeNullableAttrDOMJIT::TestDOMJITNodeNullableAttrDOMJIT):
(WebCore::jsTestDOMJITPrototypeFunctionGetAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionGetAttributeCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionItem):
(WebCore::jsTestDOMJITPrototypeFunctionItemCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionItem):
(WebCore::jsTestDOMJITPrototypeFunctionHasAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionHasAttributeCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionHasAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementById):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementByIdCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementById):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementsByName):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementsByNameCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementsByName):

  • bindings/scripts/test/TestDOMJIT.idl:
  • dom/Element.idl:
  • domjit/DOMJITAbstractHeapRepository.yaml: Added.
  • domjit/DOMJITIDLConvert.h: Added.

(WebCore::DOMJIT::DirectConverter<IDLDOMString>::directConvert<StringConversionConfiguration::Normal>):

  • domjit/DOMJITIDLType.h: Added.
  • domjit/DOMJITIDLTypeFilter.h: Added.
  • domjit/JSDocumentDOMJIT.cpp:

(WebCore::DocumentDocumentElementDOMJIT::callDOMGetter):

  • domjit/JSNodeDOMJIT.cpp:

(WebCore::NodeFirstChildDOMJIT::callDOMGetter):
(WebCore::NodeLastChildDOMJIT::callDOMGetter):
(WebCore::NodeNextSiblingDOMJIT::callDOMGetter):
(WebCore::NodePreviousSiblingDOMJIT::callDOMGetter):
(WebCore::NodeParentNodeDOMJIT::callDOMGetter):
(WebCore::NodeOwnerDocumentDOMJIT::callDOMGetter):

  • domjit/generate-abstract-heap.rb: Added.

LayoutTests:

  • js/dom/domjit-accessor-licm.html:
  • js/dom/domjit-function-effect-should-overlap-with-call-expected.txt: Added.
  • js/dom/domjit-function-effect-should-overlap-with-call.html: Added.
  • js/dom/domjit-function-expected.txt: Added.
  • js/dom/domjit-function-licm-expected.txt: Added.
  • js/dom/domjit-function-licm.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
  • js/dom/domjit-function-type-contradiction-expected.txt: Added.
  • js/dom/domjit-function-type-contradiction.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
  • js/dom/domjit-function-type-failure-expected.txt: Added.
  • js/dom/domjit-function-type-failure.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
  • js/dom/domjit-function.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r208235 r208320  
    6363class Patchpoint;
    6464class CallDOMGetterPatchpoint;
     65class Signature;
    6566}
    6667
     
    653654   
    654655    void convertToDirectCall(FrozenValue*);
     656
     657    void convertToCallDOM(Graph&);
    655658   
    656659    JSValue asJSValue()
     
    14651468        case LoadFromJSMapBucket:
    14661469        case CallDOMGetter:
     1470        case CallDOM:
    14671471            return true;
    14681472        default:
     
    19821986        return isInt32Speculation(prediction());
    19831987    }
     1988
     1989    bool shouldSpeculateNotInt32()
     1990    {
     1991        return isNotInt32Speculation(prediction());
     1992    }
    19841993   
    19851994    bool sawBooleans()
     
    20412050    {
    20422051        return isBooleanSpeculation(prediction());
     2052    }
     2053
     2054    bool shouldSpeculateNotBoolean()
     2055    {
     2056        return isNotBooleanSpeculation(prediction());
    20432057    }
    20442058   
     
    20662080    {
    20672081        return isStringSpeculation(prediction());
     2082    }
     2083
     2084    bool shouldSpeculateNotString()
     2085    {
     2086        return isNotStringSpeculation(prediction());
    20682087    }
    20692088 
     
    23672386    {
    23682387        return m_opInfo2.as<const ClassInfo*>();
     2388    }
     2389
     2390    bool hasSignature() const
     2391    {
     2392        // Note that this does not include TailCall node types intentionally.
     2393        // CallDOM node types are always converted from Call.
     2394        return op() == Call || op() == CallDOM;
     2395    }
     2396
     2397    const DOMJIT::Signature* signature()
     2398    {
     2399        return m_opInfo.as<const DOMJIT::Signature*>();
    23692400    }
    23702401
Note: See TracChangeset for help on using the changeset viewer.