Changeset 206846 in webkit


Ignore:
Timestamp:
Oct 5, 2016 10:20:10 PM (8 years ago)
Author:
Yusuke Suzuki
Message:

[DOMJIT] Add initial CheckDOM and CallDOM implementations
https://bugs.webkit.org/show_bug.cgi?id=162941

Reviewed by Filip Pizlo.

JSTests:

  • stress/domjit-getter-poly.js: Added.

(shouldBe):
(access):

  • stress/domjit-getter-proto.js: Added.

(shouldBe):
(access):

  • stress/domjit-getter-super-poly.js: Added.

(shouldBe):
(access):

  • stress/domjit-getter.js: Added.

(shouldBe):
(access):

Source/JavaScriptCore:

This patch implements a prototype of DOMJIT accelerated getter.
We add two new DFG nodes, CheckDOM and CallDOM.

CheckDOM is used to filter inappropriate |this| object for DOM getter. Its functionality
is equivalent to jsDynamicCast's Check. You can use like "CheckDOM, @1, JSNode::info()",
and this CheckDOM incurs a BadType exit if the class of the given @1 is not a subclass of
JSNode::info().

CallDOM is used to emit actual DOM operations. It takes GlobalObject and checked DOM
object. And it returns JSValue as its result.

Both CheckDOM and CallDOM can take a DOMJIT::Patchpoint. This is somewhat code snippet
generator, and is injectable to DFG and FTL. DFG and FTL set up registers correctly
according to DOMJIT::Patchpoint's requirement and invoke this patchpoint generator to emit code.
While CallDOM always requires a patchpoint, ideally CheckDOM does not require it since
isSubclassOf check can be implemented in DFG / FTL side. However, some classes have a
faster way to query isSubclassOf. For example, JSNode in WebCore introduces a special
JSType to optimize this query. CheckDOM's patchpoint gives us a chance to emit special
faster code for such a case.

By leveraging above nodes, we can construct DOMJIT accelerated getter. When DFG recognizes the
given getter call is CustomGetter and it has DOMJIT::GetterSetter information, DFG emits the above nodes.
We implemented a prototype in jsc.cpp shell as DOMJITGetter to test the functionality.

Notes about the future extensions.

  1. Currently, we do not allow CallDOM to emit any function calls. This will be extended by adding addSlowPathCall functionality to DOMJIT::Patchpoint later. Interesting thing is that we need to create an abstraction over DFG slow path call and FTL slow path call!
  1. CheckDOM is not handled in DFGTypeCheckHoistingPhase yet. And we have a chance to merge several CheckDOM into one. For example, given CheckDOM A and CheckDOM B to the same target. If A is subclass of B, we can merge them to CheckDOM A.

(JSC::B3::Effects::forCheck):

  • b3/B3Value.cpp:

(JSC::B3::Value::effects):

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::dump):

  • bytecode/GetByIdStatus.h:

(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::isCustom):
(JSC::GetByIdStatus::takesSlowPath):
(JSC::GetByIdStatus::isSimple): Deleted.

  • bytecode/SpeculatedType.cpp:

(JSC::speculationFromClassInfo):

  • dfg/DFGAbstractInterpreter.h:

(JSC::DFG::AbstractInterpreter::filterClassInfo):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGAbstractValue.cpp:

(JSC::DFG::AbstractValue::filterClassInfo):

  • dfg/DFGAbstractValue.h:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleDOMJITGetter):
(JSC::DFG::ByteCodeParser::handleGetById):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasDOMJIT):
(JSC::DFG::Node::domJIT):
(JSC::DFG::Node::hasClassInfo):
(JSC::DFG::Node::classInfo):
(JSC::DFG::Node::OpInfoWrapper::OpInfoWrapper):
(JSC::DFG::Node::OpInfoWrapper::operator=):

  • dfg/DFGNodeType.h:
  • dfg/DFGOpInfo.h:

(JSC::DFG::OpInfo::OpInfo):

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::allocateTemporaryRegistersForPatchpoint):
(JSC::DFG::SpeculativeJIT::compileCallDOM):
(JSC::DFG::SpeculativeJIT::compileCheckDOM):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStructureAbstractValue.cpp:

(JSC::DFG::StructureAbstractValue::filterClassInfoSlow):
(JSC::DFG::StructureAbstractValue::isSubClassOf):

  • dfg/DFGStructureAbstractValue.h:

(JSC::DFG::StructureAbstractValue::filterClassInfo):
(JSC::DFG::StructureAbstractValue::filter): Deleted.

  • domjit/DOMJITPatchpointParams.h: Copied from Source/JavaScriptCore/dfg/DFGOpInfo.h.

(JSC::DOMJIT::PatchpointParams::~PatchpointParams):
(JSC::DOMJIT::PatchpointParams::size):
(JSC::DOMJIT::PatchpointParams::at):
(JSC::DOMJIT::PatchpointParams::operator[]):
(JSC::DOMJIT::PatchpointParams::gpScratch):
(JSC::DOMJIT::PatchpointParams::fpScratch):
(JSC::DOMJIT::PatchpointParams::PatchpointParams):

  • domjit/DOMJITReg.h: Added.

(JSC::DOMJIT::Reg::Reg):
(JSC::DOMJIT::Reg::isGPR):
(JSC::DOMJIT::Reg::isFPR):
(JSC::DOMJIT::Reg::isJSValueRegs):
(JSC::DOMJIT::Reg::gpr):
(JSC::DOMJIT::Reg::fpr):
(JSC::DOMJIT::Reg::jsValueRegs):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileUnreachable): Deleted.

  • jit/AssemblyHelpers.h:
  • jsc.cpp:

(WTF::DOMJITNode::DOMJITNode):
(WTF::DOMJITNode::createStructure):
(WTF::DOMJITNode::create):
(WTF::DOMJITNode::value):
(WTF::DOMJITNode::offsetOfValue):
(WTF::DOMJITGetter::DOMJITGetter):
(WTF::DOMJITGetter::createStructure):
(WTF::DOMJITGetter::create):
(WTF::DOMJITGetter::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
(WTF::DOMJITGetter::domJITNodeGetterSetter):
(WTF::DOMJITGetter::finishCreation):
(WTF::DOMJITGetter::customGetter):
(GlobalObject::finishCreation):
(functionCreateDOMJITNodeObject):
(functionCreateDOMJITGetterObject):

Source/WTF:

  • wtf/Box.h:

(WTF::Box::Box):

Location:
trunk
Files:
5 added
34 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r206804 r206846  
     12016-10-05  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Add initial CheckDOM and CallDOM implementations
     4        https://bugs.webkit.org/show_bug.cgi?id=162941
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * stress/domjit-getter-poly.js: Added.
     9        (shouldBe):
     10        (access):
     11        * stress/domjit-getter-proto.js: Added.
     12        (shouldBe):
     13        (access):
     14        * stress/domjit-getter-super-poly.js: Added.
     15        (shouldBe):
     16        (access):
     17        * stress/domjit-getter.js: Added.
     18        (shouldBe):
     19        (access):
     20
    1212016-10-04  Saam Barati  <sbarati@apple.com>
    222
  • trunk/Source/JavaScriptCore/ChangeLog

    r206844 r206846  
     12016-10-05  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Add initial CheckDOM and CallDOM implementations
     4        https://bugs.webkit.org/show_bug.cgi?id=162941
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch implements a prototype of DOMJIT accelerated getter.
     9        We add two new DFG nodes, CheckDOM and CallDOM.
     10
     11        CheckDOM is used to filter inappropriate |this| object for DOM getter. Its functionality
     12        is equivalent to jsDynamicCast's Check. You can use like "CheckDOM, @1, JSNode::info()",
     13        and this CheckDOM incurs a BadType exit if the class of the given @1 is not a subclass of
     14        JSNode::info().
     15
     16        CallDOM is used to emit actual DOM operations. It takes GlobalObject and checked DOM
     17        object. And it returns JSValue as its result.
     18
     19        Both CheckDOM and CallDOM can take a DOMJIT::Patchpoint. This is somewhat code snippet
     20        generator, and is injectable to DFG and FTL. DFG and FTL set up registers correctly
     21        according to DOMJIT::Patchpoint's requirement and invoke this patchpoint generator to emit code.
     22        While CallDOM always requires a patchpoint, ideally CheckDOM does not require it since
     23        isSubclassOf check can be implemented in DFG / FTL side. However, some classes have a
     24        faster way to query isSubclassOf. For example, JSNode in WebCore introduces a special
     25        JSType to optimize this query. CheckDOM's patchpoint gives us a chance to emit special
     26        faster code for such a case.
     27
     28        By leveraging above nodes, we can construct DOMJIT accelerated getter. When DFG recognizes the
     29        given getter call is CustomGetter and it has DOMJIT::GetterSetter information, DFG emits the above nodes.
     30        We implemented a prototype in jsc.cpp shell as DOMJITGetter to test the functionality.
     31
     32        Notes about the future extensions.
     33
     34        1. Currently, we do not allow CallDOM to emit any function calls. This will be extended by
     35           adding `addSlowPathCall` functionality to DOMJIT::Patchpoint later. Interesting thing is that
     36           we need to create an abstraction over DFG slow path call and FTL slow path call!
     37
     38        2. CheckDOM is not handled in DFGTypeCheckHoistingPhase yet. And we have a chance to merge several CheckDOM into one.
     39           For example, given CheckDOM A and CheckDOM B to the same target. If A is subclass of B, we can merge them to CheckDOM A.
     40
     41        * JavaScriptCore.xcodeproj/project.pbxproj:
     42        * b3/B3Effects.h:
     43        (JSC::B3::Effects::forCheck):
     44        * b3/B3Value.cpp:
     45        (JSC::B3::Value::effects):
     46        * bytecode/GetByIdStatus.cpp:
     47        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
     48        (JSC::GetByIdStatus::makesCalls):
     49        (JSC::GetByIdStatus::dump):
     50        * bytecode/GetByIdStatus.h:
     51        (JSC::GetByIdStatus::GetByIdStatus):
     52        (JSC::GetByIdStatus::isCustom):
     53        (JSC::GetByIdStatus::takesSlowPath):
     54        (JSC::GetByIdStatus::isSimple): Deleted.
     55        * bytecode/SpeculatedType.cpp:
     56        (JSC::speculationFromClassInfo):
     57        * dfg/DFGAbstractInterpreter.h:
     58        (JSC::DFG::AbstractInterpreter::filterClassInfo):
     59        * dfg/DFGAbstractInterpreterInlines.h:
     60        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     61        (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterClassInfo):
     62        * dfg/DFGAbstractValue.cpp:
     63        (JSC::DFG::AbstractValue::filterClassInfo):
     64        * dfg/DFGAbstractValue.h:
     65        * dfg/DFGByteCodeParser.cpp:
     66        (JSC::DFG::ByteCodeParser::handleDOMJITGetter):
     67        (JSC::DFG::ByteCodeParser::handleGetById):
     68        * dfg/DFGClobberize.h:
     69        (JSC::DFG::clobberize):
     70        * dfg/DFGConstantFoldingPhase.cpp:
     71        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     72        * dfg/DFGDoesGC.cpp:
     73        (JSC::DFG::doesGC):
     74        * dfg/DFGFixupPhase.cpp:
     75        (JSC::DFG::FixupPhase::fixupNode):
     76        * dfg/DFGNode.h:
     77        (JSC::DFG::Node::hasHeapPrediction):
     78        (JSC::DFG::Node::hasDOMJIT):
     79        (JSC::DFG::Node::domJIT):
     80        (JSC::DFG::Node::hasClassInfo):
     81        (JSC::DFG::Node::classInfo):
     82        (JSC::DFG::Node::OpInfoWrapper::OpInfoWrapper):
     83        (JSC::DFG::Node::OpInfoWrapper::operator=):
     84        * dfg/DFGNodeType.h:
     85        * dfg/DFGOpInfo.h:
     86        (JSC::DFG::OpInfo::OpInfo):
     87        * dfg/DFGPredictionPropagationPhase.cpp:
     88        * dfg/DFGSafeToExecute.h:
     89        (JSC::DFG::safeToExecute):
     90        * dfg/DFGSpeculativeJIT.cpp:
     91        (JSC::DFG::allocateTemporaryRegistersForPatchpoint):
     92        (JSC::DFG::SpeculativeJIT::compileCallDOM):
     93        (JSC::DFG::SpeculativeJIT::compileCheckDOM):
     94        * dfg/DFGSpeculativeJIT.h:
     95        * dfg/DFGSpeculativeJIT32_64.cpp:
     96        (JSC::DFG::SpeculativeJIT::compile):
     97        * dfg/DFGSpeculativeJIT64.cpp:
     98        (JSC::DFG::SpeculativeJIT::compile):
     99        * dfg/DFGStructureAbstractValue.cpp:
     100        (JSC::DFG::StructureAbstractValue::filterClassInfoSlow):
     101        (JSC::DFG::StructureAbstractValue::isSubClassOf):
     102        * dfg/DFGStructureAbstractValue.h:
     103        (JSC::DFG::StructureAbstractValue::filterClassInfo):
     104        (JSC::DFG::StructureAbstractValue::filter): Deleted.
     105        * domjit/DOMJITPatchpointParams.h: Copied from Source/JavaScriptCore/dfg/DFGOpInfo.h.
     106        (JSC::DOMJIT::PatchpointParams::~PatchpointParams):
     107        (JSC::DOMJIT::PatchpointParams::size):
     108        (JSC::DOMJIT::PatchpointParams::at):
     109        (JSC::DOMJIT::PatchpointParams::operator[]):
     110        (JSC::DOMJIT::PatchpointParams::gpScratch):
     111        (JSC::DOMJIT::PatchpointParams::fpScratch):
     112        (JSC::DOMJIT::PatchpointParams::PatchpointParams):
     113        * domjit/DOMJITReg.h: Added.
     114        (JSC::DOMJIT::Reg::Reg):
     115        (JSC::DOMJIT::Reg::isGPR):
     116        (JSC::DOMJIT::Reg::isFPR):
     117        (JSC::DOMJIT::Reg::isJSValueRegs):
     118        (JSC::DOMJIT::Reg::gpr):
     119        (JSC::DOMJIT::Reg::fpr):
     120        (JSC::DOMJIT::Reg::jsValueRegs):
     121        * ftl/FTLCapabilities.cpp:
     122        (JSC::FTL::canCompile):
     123        * ftl/FTLLowerDFGToB3.cpp:
     124        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     125        (JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
     126        (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
     127        (JSC::FTL::DFG::LowerDFGToB3::compileUnreachable): Deleted.
     128        * jit/AssemblyHelpers.h:
     129        * jsc.cpp:
     130        (WTF::DOMJITNode::DOMJITNode):
     131        (WTF::DOMJITNode::createStructure):
     132        (WTF::DOMJITNode::create):
     133        (WTF::DOMJITNode::value):
     134        (WTF::DOMJITNode::offsetOfValue):
     135        (WTF::DOMJITGetter::DOMJITGetter):
     136        (WTF::DOMJITGetter::createStructure):
     137        (WTF::DOMJITGetter::create):
     138        (WTF::DOMJITGetter::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
     139        (WTF::DOMJITGetter::domJITNodeGetterSetter):
     140        (WTF::DOMJITGetter::finishCreation):
     141        (WTF::DOMJITGetter::customGetter):
     142        (GlobalObject::finishCreation):
     143        (functionCreateDOMJITNodeObject):
     144        (functionCreateDOMJITGetterObject):
     145
    11462016-10-05  Yusuke Suzuki  <utatane.tea@gmail.com>
    2147
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r206779 r206846  
    20992099                E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */; };
    21002100                E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = E3794E741B77EB97005543AE /* ModuleAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2101                E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2102                E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83B1DA4928000F3D412 /* DOMJITReg.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21012103                E3963CEE1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */; };
    21022104                E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    43984400                E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleAnalyzer.cpp; sourceTree = "<group>"; };
    43994401                E3794E741B77EB97005543AE /* ModuleAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleAnalyzer.h; sourceTree = "<group>"; };
     4402                E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpointParams.h; sourceTree = "<group>"; };
     4403                E37AD83B1DA4928000F3D412 /* DOMJITReg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITReg.h; sourceTree = "<group>"; };
    44004404                E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesAnalyzeModule.cpp; sourceTree = "<group>"; };
    44014405                E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; };
     
    71847188                                E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */,
    71857189                                E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */,
     7190                                E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
     7191                                E37AD83B1DA4928000F3D412 /* DOMJITReg.h */,
    71867192                        );
    71877193                        path = domjit;
     
    76017607                                0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
    76027608                                0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */,
     7609                                E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */,
    76037610                                0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */,
    76047611                                0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */,
     
    84298436                                79B1788E1D399B8000B1A567 /* JITMathICForwards.h in Headers */,
    84308437                                451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
     8438                                E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */,
    84318439                                86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
    84328440                                86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
  • trunk/Source/JavaScriptCore/b3/B3Effects.h

    r206739 r206846  
    7979    }
    8080
     81    static Effects forCheck()
     82    {
     83        Effects result;
     84        result.exitsSideways = true;
     85        // The program could read anything after exiting, and it's on us to declare this.
     86        result.reads = HeapRange::top();
     87        return result;
     88    }
     89
    8190    bool mustExecute() const
    8291    {
  • trunk/Source/JavaScriptCore/b3/B3Value.cpp

    r206739 r206846  
    615615    case CheckMul:
    616616    case Check:
    617         result.exitsSideways = true;
    618         // The program could read anything after exiting, and it's on us to declare this.
    619         result.reads = HeapRange::top();
     617        result = Effects::forCheck();
    620618        break;
    621619    case Upsilon:
  • trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp

    r206844 r206846  
    247247                    if (!domJIT)
    248248                        return GetByIdStatus(slowPathState, true);
     249                    result.m_state = Custom;
    249250                    break;
    250251                }
     
    264265                if (!result.appendVariant(variant))
    265266                    return GetByIdStatus(slowPathState, true);
     267
     268                if (domJIT) {
     269                    // Give up when cutom accesses are not merged into one.
     270                    if (result.numVariants() != 1)
     271                        return GetByIdStatus(slowPathState, true);
     272                } else {
     273                    // Give up when custom access and simple access are mixed.
     274                    if (result.m_state == Custom)
     275                        return GetByIdStatus(slowPathState, true);
     276                }
    266277                break;
    267278            } }
     
    363374    case NoInformation:
    364375    case TakesSlowPath:
     376    case Custom:
    365377        return false;
    366378    case Simple:
     
    404416        out.print("Simple");
    405417        break;
     418    case Custom:
     419        out.print("Custom");
     420        break;
    406421    case TakesSlowPath:
    407422        out.print("TakesSlowPath");
  • trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.h

    r206525 r206846  
    4545        Simple,         // It's cached for a simple access to a known object property with
    4646                        // a possible structure chain and a possible specific value.
     47        Custom,         // It's cached for a custom accessor with a possible structure chain.
    4748        TakesSlowPath,  // It's known to often take slow path.
    4849        MakesCalls      // It's known to take paths that make calls.
     
    6566        , m_wasSeenInJIT(wasSeenInJIT)
    6667    {
    67         ASSERT((state == Simple) == variant.isSet());
     68        ASSERT((state == Simple || state == Custom) == variant.isSet());
    6869        m_variants.append(variant);
    6970    }
     
    8384    bool operator!() const { return !isSet(); }
    8485    bool isSimple() const { return m_state == Simple; }
     86    bool isCustom() const { return m_state == Custom; }
    8587
    8688    size_t numVariants() const { return m_variants.size(); }
     
    8991    const GetByIdVariant& operator[](size_t index) const { return at(index); }
    9092
    91     bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
     93    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom; }
    9294    bool makesCalls() const;
    9395   
  • trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp

    r206267 r206846  
    354354SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
    355355{
     356    if (classInfo == JSString::info())
     357        return SpecString;
     358
     359    if (classInfo == Symbol::info())
     360        return SpecSymbol;
     361
    356362    if (classInfo == JSFinalObject::info())
    357363        return SpecFinalObject;
     
    386392    if (isTypedView(classInfo->typedArrayStorageType))
    387393        return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
     394
     395    if (classInfo->isSubClassOf(JSArray::info()))
     396        return SpecDerivedArray;
    388397   
    389398    if (classInfo->isSubClassOf(JSObject::info()))
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h

    r206525 r206846  
    135135    }
    136136   
     137    template<typename T>
     138    FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
     139    {
     140        return filterClassInfo(forNode(node), classInfo);
     141    }
     142
    137143    FiltrationResult filter(AbstractValue&, const StructureSet&, SpeculatedType admittedTypes = SpecNone);
    138144    FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
    139145    FiltrationResult filter(AbstractValue&, SpeculatedType);
    140146    FiltrationResult filterByValue(AbstractValue&, FrozenValue);
     147    FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
    141148   
    142149    PhiChildren* phiChildren() { return m_phiChildren.get(); }
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r206804 r206846  
    3030#include "ArrayConstructor.h"
    3131#include "DFGAbstractInterpreter.h"
     32#include "DOMJITGetterSetter.h"
    3233#include "GetByIdStatus.h"
    3334#include "GetterSetter.h"
     
    22682269    case ReallocatePropertyStorage:
    22692270        forNode(node).clear(); // The result is not a JS value.
     2271        break;
     2272    case CheckDOM: {
     2273        JSValue constant = forNode(node->child1()).value();
     2274        if (constant) {
     2275            if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
     2276                m_state.setFoundConstants(true);
     2277                ASSERT(constant);
     2278                break;
     2279            }
     2280        }
     2281
     2282        AbstractValue& value = forNode(node->child1());
     2283
     2284        if (value.m_structure.isSubClassOf(node->classInfo()))
     2285            m_state.setFoundConstants(true);
     2286
     2287        filterClassInfo(value, node->classInfo());
     2288        break;
     2289    }
     2290    case CallDOM:
     2291        clobberWorld(node->origin.semantic, clobberLimit);
     2292        forNode(node).makeBytecodeTop();
    22702293        break;
    22712294    case CheckArray: {
     
    30573080
    30583081template<typename AbstractStateType>
     3082FiltrationResult AbstractInterpreter<AbstractStateType>::filterClassInfo(
     3083    AbstractValue& value, const ClassInfo* classInfo)
     3084{
     3085    if (value.filterClassInfo(m_graph, classInfo) == FiltrationOK)
     3086        return FiltrationOK;
     3087    m_state.setIsValid(false);
     3088    return Contradiction;
     3089}
     3090
     3091template<typename AbstractStateType>
    30593092void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double))
    30603093{
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp

    r205254 r206846  
    307307}
    308308
     309FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
     310{
     311    // FIXME: AI should track ClassInfo to leverage hierarchical class information.
     312    // https://bugs.webkit.org/show_bug.cgi?id=162989
     313    if (isClear())
     314        return FiltrationOK;
     315
     316    m_type &= speculationFromClassInfo(classInfo);
     317    m_structure.filterClassInfo(classInfo);
     318
     319    m_structure.filter(m_type);
     320
     321    filterArrayModesByType();
     322    filterValueByType();
     323    return normalizeClarity(graph);
     324}
     325
    309326FiltrationResult AbstractValue::filter(SpeculatedType type)
    310327{
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractValue.h

    r206525 r206846  
    308308    FiltrationResult filterByValue(const FrozenValue& value);
    309309    FiltrationResult filter(const AbstractValue&);
     310    FiltrationResult filterClassInfo(Graph&, const ClassInfo*);
    310311
    311312    FiltrationResult filter(Graph&, const InferredType::Descriptor&);
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r206804 r206846  
    220220    Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&, Node* value);
    221221    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&, NodeType = GetByOffset);
     222    bool handleDOMJITGetter(int resultOperand, const GetByIdVariant&, Node* thisNode, SpeculatedType prediction);
    222223
    223224    // Create a presence ObjectPropertyCondition based on some known offset and structure set. Does not
     
    26742675}
    26752676
     2677bool ByteCodeParser::handleDOMJITGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, SpeculatedType prediction)
     2678{
     2679    if (!variant.domJIT())
     2680        return false;
     2681
     2682    DOMJIT::GetterSetter* domJIT = variant.domJIT();
     2683
     2684    // We do not need to actually look up CustomGetterSetter here. Checking Structures or registering watchpoints are enough,
     2685    // since replacement of CustomGetterSetter always incurs Structure transition.
     2686    if (!check(variant.conditionSet()))
     2687        return false;
     2688    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), thisNode);
     2689
     2690    // We do not need to emit CheckCell thingy here. When the custom accessor is replaced to different one, Structure transition occurs.
     2691    addToGraph(CheckDOM, OpInfo(domJIT), OpInfo(domJIT->thisClassInfo()), thisNode);
     2692    Node* globalObject = addToGraph(GetGlobalObject, thisNode);
     2693    addVarArgChild(globalObject); // GlobalObject of thisNode is always used to create a DOMWrapper.
     2694    addVarArgChild(thisNode);
     2695    set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(domJIT), OpInfo(prediction)));
     2696    return true;
     2697}
     2698
    26762699template<typename ChecksFunctor>
    26772700bool ByteCodeParser::handleTypedArrayConstructor(
     
    32673290    else
    32683291        getById = TryGetById;
     3292
     3293    // Special path for custom accessors since custom's offset does not have any meanings.
     3294    // So, this is completely different from Simple one. But we have a chance to optimize it when we use DOMJIT.
     3295    if (getByIdStatus.isCustom()) {
     3296        ASSERT(getByIdStatus.numVariants() == 1);
     3297        ASSERT(!getByIdStatus.makesCalls());
     3298        GetByIdVariant variant = getByIdStatus[0];
     3299        ASSERT(variant.domJIT());
     3300        if (handleDOMJITGetter(destinationOperand, variant, base, prediction)) {
     3301            if (m_graph.compilation())
     3302                m_graph.compilation()->noticeInlinedGetById();
     3303            return;
     3304        }
     3305    }
    32693306
    32703307    ASSERT(type == AccessType::Get || !getByIdStatus.makesCalls());
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r206804 r206846  
    886886        return;
    887887
     888    case CheckDOM:
     889        def(PureValue(node, node->classInfo()));
     890        return;
     891
     892    case CallDOM:
     893        read(World);
     894        write(Heap);
     895        return;
     896
    888897    case Arrayify:
    889898    case ArrayifyToStructure:
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r203895 r206846  
    159159                break;
    160160            }
     161
     162            case CheckDOM: {
     163                JSValue constant = m_state.forNode(node->child1()).value();
     164                if (constant) {
     165                    if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
     166                        m_interpreter.execute(indexInBlock);
     167                        node->remove();
     168                        eliminated = true;
     169                        break;
     170                    }
     171                }
     172
     173                AbstractValue& value = m_state.forNode(node->child1());
     174
     175                if (value.m_structure.isSubClassOf(node->classInfo())) {
     176                    m_interpreter.execute(indexInBlock);
     177                    node->remove();
     178                    eliminated = true;
     179                    break;
     180                }
     181                break;
     182            }
    161183               
    162184            case GetIndexedPropertyStorage: {
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r206804 r206846  
    119119    case GetExecutable:
    120120    case GetButterfly:
     121    case CallDOM:
     122    case CheckDOM:
    121123    case CheckArray:
    122124    case GetScope:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r206804 r206846  
    16991699            break;
    17001700        }
     1701
     1702        case CheckDOM:
     1703            fixEdge<CellUse>(node->child1());
     1704            break;
     1705
     1706        case CallDOM:
     1707            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0)); // GlobalObject.
     1708            fixEdge<CellUse>(m_graph.varArgChild(node, 1)); // DOM.
     1709            break;
    17011710
    17021711#if !ASSERT_DISABLED
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r206779 r206846  
    14471447        case ToNumber:
    14481448        case LoadFromJSMapBucket:
     1449        case CallDOM:
    14491450            return true;
    14501451        default:
     
    23132314        return m_opInfo.as<BasicBlockLocation*>();
    23142315    }
    2315    
     2316
     2317    bool hasDOMJIT() const
     2318    {
     2319        return op() == CheckDOM || op() == CallDOM;
     2320    }
     2321
     2322    DOMJIT::GetterSetter* domJIT()
     2323    {
     2324        ASSERT(hasDOMJIT());
     2325        return m_opInfo.as<DOMJIT::GetterSetter*>();
     2326    }
     2327
     2328    bool hasClassInfo() const
     2329    {
     2330        return op() == CheckDOM;
     2331    }
     2332
     2333    const ClassInfo* classInfo()
     2334    {
     2335        return m_opInfo2.as<const ClassInfo*>();
     2336    }
     2337
    23162338    Node* replacement() const
    23172339    {
     
    23932415            u.pointer = pointer;
    23942416        }
     2417        OpInfoWrapper(const void* constPointer)
     2418        {
     2419            u.int64 = 0;
     2420            u.constPointer = constPointer;
     2421        }
    23952422        OpInfoWrapper& operator=(uint32_t int32)
    23962423        {
     
    24162443            return *this;
    24172444        }
     2445        OpInfoWrapper& operator=(const void* constPointer)
     2446        {
     2447            u.int64 = 0;
     2448            u.constPointer = constPointer;
     2449            return *this;
     2450        }
    24182451        template <typename T>
    2419         ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value, T>::type
     2452        ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
    24202453        {
    24212454            return static_cast<T>(u.pointer);
     2455        }
     2456        template <typename T>
     2457        ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
     2458        {
     2459            return static_cast<T>(u.constPointer);
    24222460        }
    24232461        template <typename T>
     
    24352473            uint64_t int64;
    24362474            void* pointer;
     2475            const void* constPointer;
    24372476        } u;
    24382477    };
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r206804 r206846  
    399399    \
    400400    macro(ToLowerCase, NodeResultJS) \
     401    /* Nodes for DOM JIT */\
     402    macro(CheckDOM, NodeMustGenerate) \
     403    macro(CallDOM, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
    401404
    402405// This enum generates a monotonically increasing id for all Node types,
  • trunk/Source/JavaScriptCore/dfg/DFGOpInfo.h

    r206525 r206846  
    4444#endif
    4545    explicit OpInfo(void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
     46    explicit OpInfo(const void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
    4647    uint64_t m_value;
    4748};
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r206804 r206846  
    700700        case GetFromArguments:
    701701        case LoadFromJSMapBucket:
    702         case ToNumber: {
     702        case ToNumber:
     703        case CallDOM: {
    703704            setPrediction(m_currentNode->getHeapPrediction());
    704705            break;
     
    824825            break;
    825826        }
     827
     828        case CheckDOM:
     829            break;
    826830
    827831        case CallObjectConstructor: {
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r206804 r206846  
    219219    case GetExecutable:
    220220    case GetButterfly:
     221    case CallDOM:
     222    case CheckDOM:
    221223    case CheckArray:
    222224    case Arrayify:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r206841 r206846  
    3939#include "DFGSaneStringGetByValSlowPathGenerator.h"
    4040#include "DFGSlowPathGenerator.h"
     41#include "DOMJITPatchpoint.h"
     42#include "DOMJITPatchpointParams.h"
    4143#include "DirectArguments.h"
    4244#include "JITAddGenerator.h"
     
    71127114}
    71137115
     7116static void allocateTemporaryRegistersForPatchpoint(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, DOMJIT::Patchpoint& patchpoint)
     7117{
     7118    for (unsigned i = 0; i < patchpoint.numGPScratchRegisters; ++i) {
     7119        GPRTemporary temporary(jit);
     7120        gpScratch.append(temporary.gpr());
     7121        gpHolders.append(WTFMove(temporary));
     7122    }
     7123
     7124    for (unsigned i = 0; i < patchpoint.numFPScratchRegisters; ++i) {
     7125        FPRTemporary temporary(jit);
     7126        fpScratch.append(temporary.fpr());
     7127        fpHolders.append(WTFMove(temporary));
     7128    }
     7129}
     7130
     7131void SpeculativeJIT::compileCallDOM(Node* node)
     7132{
     7133    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->callDOM();
     7134
     7135    Vector<GPRReg> gpScratch;
     7136    Vector<FPRReg> fpScratch;
     7137    Vector<DOMJIT::Reg> regs;
     7138
     7139    // FIXME: patchpoint should have a way to tell this can reuse "base" register.
     7140    // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
     7141    SpeculateCellOperand globalObject(this, m_jit.graph().varArgChild(node, 0));
     7142    SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 1));
     7143    JSValueRegsTemporary result(this);
     7144
     7145    regs.append(result.regs());
     7146    regs.append(globalObject.gpr());
     7147    regs.append(base.gpr());
     7148#if USE(JSVALUE64)
     7149    regs.append(static_cast<GPRReg>(GPRInfo::tagMaskRegister));
     7150    regs.append(static_cast<GPRReg>(GPRInfo::tagTypeNumberRegister));
     7151#endif
     7152
     7153    Vector<GPRTemporary> gpTempraries;
     7154    Vector<FPRTemporary> fpTempraries;
     7155    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
     7156    DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     7157    patchpoint->generator()->run(m_jit, params);
     7158    jsValueResult(result.regs(), node);
     7159}
     7160
     7161void SpeculativeJIT::compileCheckDOM(Node* node)
     7162{
     7163    // FIXME: We can add the fallback implementation that inlines jsDynamicCast things here.
     7164    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->checkDOM();
     7165
     7166    Vector<GPRReg> gpScratch;
     7167    Vector<FPRReg> fpScratch;
     7168    Vector<DOMJIT::Reg> regs;
     7169
     7170    SpeculateCellOperand base(this, node->child1());
     7171    GPRReg baseGPR = base.gpr();
     7172    regs.append(baseGPR);
     7173
     7174    Vector<GPRTemporary> gpTempraries;
     7175    Vector<FPRTemporary> fpTempraries;
     7176    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
     7177
     7178    DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     7179    CCallHelpers::JumpList failureCases = patchpoint->generator()->run(m_jit, params);
     7180    speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
     7181    noResult(node);
     7182}
     7183
    71147184GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
    71157185{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r206804 r206846  
    25442544    void compileReallocatePropertyStorage(Node*);
    25452545    void compileGetButterfly(Node*);
     2546    void compileCallDOM(Node*);
     2547    void compileCheckDOM(Node*);
    25462548   
    25472549#if USE(JSVALUE32_64)
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r206804 r206846  
    54365436    }
    54375437
     5438    case CallDOM:
     5439        compileCallDOM(node);
     5440        break;
     5441
     5442    case CheckDOM:
     5443        compileCheckDOM(node);
     5444        break;
     5445
    54385446    case Unreachable:
    54395447        unreachable(node);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r206804 r206846  
    55675567        break;
    55685568
     5569    case CallDOM:
     5570        compileCallDOM(node);
     5571        break;
     5572
     5573    case CheckDOM:
     5574        compileCheckDOM(node);
     5575        break;
     5576
    55695577#if ENABLE(FTL_JIT)       
    55705578    case CheckTierUpInLoop: {
  • trunk/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.cpp

    r198364 r206846  
    259259}
    260260
     261void StructureAbstractValue::filterClassInfoSlow(const ClassInfo* classInfo)
     262{
     263    ASSERT(!isTop());
     264    m_set.genericFilter(
     265        [&] (Structure* structure) {
     266            return structure->classInfo()->isSubClassOf(classInfo);
     267        });
     268}
     269
    261270bool StructureAbstractValue::contains(Structure* structure) const
    262271{
     
    320329}
    321330
     331bool StructureAbstractValue::isSubClassOf(const ClassInfo* classInfo) const
     332{
     333    if (isInfinite())
     334        return false;
     335
     336    // Note taht this function returns true if the structure set is empty.
     337    for (const Structure* structure : m_set) {
     338        if (!structure->classInfo()->isSubClassOf(classInfo))
     339            return false;
     340    }
     341    return true;
     342}
     343
    322344bool StructureAbstractValue::equalsSlow(const StructureAbstractValue& other) const
    323345{
  • trunk/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h

    r206525 r206846  
    164164            filterSlow(type);
    165165    }
     166
     167    ALWAYS_INLINE void filterClassInfo(const ClassInfo* classInfo)
     168    {
     169        if (isNeitherClearNorTop())
     170            filterClassInfoSlow(classInfo);
     171    }
    166172   
    167173    ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const
     
    232238    bool overlaps(const StructureSet& other) const;
    233239    bool overlaps(const StructureAbstractValue& other) const;
     240
     241    bool isSubClassOf(const ClassInfo*) const;
    234242   
    235243    void validateReferences(const TrackedReferences&) const;
     
    242250   
    243251    void filterSlow(SpeculatedType type);
     252    void filterClassInfoSlow(const ClassInfo*);
    244253    bool mergeSlow(const StructureAbstractValue& other);
    245254   
  • trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h

    r206844 r206846  
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
    2626#pragma once
    2727
    28 #include <wtf/StdLibExtras.h>
     28#if ENABLE(JIT)
    2929
    30 #if ENABLE(DFG_JIT)
     30#include "CCallHelpers.h"
     31#include "DOMJITReg.h"
     32#include "RegisterSet.h"
    3133
    32 namespace JSC { namespace DFG {
     34namespace JSC { namespace DOMJIT {
    3335
    34 // This type used in passing an immediate argument to Node constructor;
    35 // distinguishes an immediate value (typically an index into a CodeBlock data structure -
    36 // a constant index, argument, or identifier) from a Node*.
    37 struct OpInfo {
    38     OpInfo() : m_value(0) { }
    39     explicit OpInfo(int32_t value) : m_value(static_cast<uint64_t>(value)) { }
    40     explicit OpInfo(uint32_t value) : m_value(static_cast<uint64_t>(value)) { }
    41     explicit OpInfo(uint64_t value) : m_value(static_cast<uint64_t>(value)) { }
    42 #if OS(DARWIN)
    43     explicit OpInfo(uintptr_t value) : m_value(static_cast<uint64_t>(value)) { }
    44 #endif
    45     explicit OpInfo(void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
    46     uint64_t m_value;
     36class PatchpointParams {
     37WTF_MAKE_NONCOPYABLE(PatchpointParams);
     38public:
     39    virtual ~PatchpointParams() { }
     40
     41    unsigned size() const { return m_regs.size(); }
     42    const Reg& at(unsigned index) const { return m_regs[index]; }
     43    const Reg& operator[](unsigned index) const { return at(index); }
     44
     45    GPRReg gpScratch(unsigned index) const { return m_gpScratch[index]; }
     46    FPRReg fpScratch(unsigned index) const { return m_fpScratch[index]; }
     47
     48    PatchpointParams(Vector<Reg>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
     49        : m_regs(WTFMove(regs))
     50        , m_gpScratch(WTFMove(gpScratch))
     51        , m_fpScratch(WTFMove(fpScratch))
     52    {
     53    }
     54
     55private:
     56
     57    Vector<Reg> m_regs;
     58    Vector<GPRReg> m_gpScratch;
     59    Vector<FPRReg> m_fpScratch;
    4760};
    4861
    49 } } // namespace JSC::DFG
     62} }
    5063
    51 #endif // ENABLE(DFG_JIT)
     64#endif
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r206804 r206846  
    267267    case DefineAccessorProperty:
    268268    case ToLowerCase:
     269    case CheckDOM:
     270    case CallDOM:
    269271        // These are OK.
    270272        break;
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r206804 r206846  
    4545#include "DFGOSRAvailabilityAnalysisPhase.h"
    4646#include "DFGOSRExitFuzz.h"
     47#include "DOMJITPatchpoint.h"
     48#include "DOMJITPatchpointParams.h"
    4749#include "DirectArguments.h"
    4850#include "FTLAbstractHeapRepository.h"
     
    10461048        case ToLowerCase:
    10471049            compileToLowerCase();
     1050            break;
     1051        case CheckDOM:
     1052            compileCheckDOM();
     1053            break;
     1054        case CallDOM:
     1055            compileCallDOM();
    10481056            break;
    10491057
     
    87128720       
    87138721        crash();
     8722    }
     8723
     8724    void compileCheckDOM()
     8725    {
     8726        LValue cell = lowCell(m_node->child1());
     8727
     8728        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->checkDOM();
     8729
     8730        PatchpointValue* patchpoint = m_out.patchpoint(Void);
     8731        patchpoint->appendSomeRegister(cell);
     8732        patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
     8733        patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
     8734
     8735        State* state = &m_ftlState;
     8736        NodeOrigin origin = m_origin;
     8737        unsigned osrExitArgumentOffset = patchpoint->numChildren();
     8738        OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(jsValueValue(cell), m_node->child1().node());
     8739        patchpoint->appendColdAnys(buildExitArguments(exitDescriptor, origin.forExit, jsValueValue(cell)));
     8740
     8741        patchpoint->setGenerator(
     8742            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     8743                Vector<GPRReg> gpScratch;
     8744                Vector<FPRReg> fpScratch;
     8745                Vector<DOMJIT::Reg> regs;
     8746
     8747                regs.append(params[0].gpr());
     8748
     8749                for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
     8750                    gpScratch.append(params.gpScratch(i));
     8751
     8752                for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
     8753                    fpScratch.append(params.fpScratch(i));
     8754
     8755                RefPtr<OSRExitHandle> handle = exitDescriptor->emitOSRExitLater(*state, BadType, origin, params, osrExitArgumentOffset);
     8756
     8757                DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     8758                CCallHelpers::JumpList failureCases = domJIT->generator()->run(jit, domJITParams);
     8759
     8760                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
     8761                    linkBuffer.link(failureCases, linkBuffer.locationOf(handle->label));
     8762                });
     8763            });
     8764        patchpoint->effects = Effects::forCheck();
     8765    }
     8766
     8767    void compileCallDOM()
     8768    {
     8769        LValue globalObject = lowCell(m_graph.varArgChild(m_node, 0));
     8770        LValue cell = lowCell(m_graph.varArgChild(m_node, 1));
     8771
     8772        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->callDOM();
     8773        PatchpointValue* patchpoint = m_out.patchpoint(Int64);
     8774        patchpoint->appendSomeRegister(globalObject);
     8775        patchpoint->appendSomeRegister(cell);
     8776        patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
     8777        patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
     8778        RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
     8779        patchpoint->clobber(RegisterSet::macroScratchRegisters());
     8780        patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
     8781        patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
     8782
     8783        patchpoint->setGenerator(
     8784            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
     8785                Vector<GPRReg> gpScratch;
     8786                Vector<FPRReg> fpScratch;
     8787                Vector<DOMJIT::Reg> regs;
     8788
     8789                // FIXME: patchpoint should have a way to tell this can reuse "base" register.
     8790                // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
     8791                regs.append(JSValueRegs(params[0].gpr()));
     8792                regs.append(params[1].gpr());
     8793                regs.append(params[2].gpr());
     8794                regs.append(params[3].gpr());
     8795                regs.append(params[4].gpr());
     8796
     8797                for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
     8798                    gpScratch.append(params.gpScratch(i));
     8799
     8800                for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
     8801                    fpScratch.append(params.fpScratch(i));
     8802
     8803                Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
     8804
     8805                DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     8806                domJIT->generator()->run(jit, domJITParams);
     8807            });
     8808        patchpoint->effects = Effects::forCall();
     8809        setJSValue(patchpoint);
    87148810    }
    87158811   
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r206555 r206846  
    12101210    enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
    12111211    enum ExceptionJumpWidth { NormalJumpWidth, FarJumpWidth };
    1212     Jump emitExceptionCheck(
     1212    JS_EXPORT_PRIVATE Jump emitExceptionCheck(
    12131213        ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth);
    1214     Jump emitNonPatchableExceptionCheck();
     1214    JS_EXPORT_PRIVATE Jump emitNonPatchableExceptionCheck();
    12151215
    12161216#if ENABLE(SAMPLING_COUNTERS)
  • trunk/Source/JavaScriptCore/jsc.cpp

    r206653 r206846  
    2929#include "CodeBlock.h"
    3030#include "Completion.h"
     31#include "DOMJITGetterSetter.h"
     32#include "DOMJITPatchpoint.h"
     33#include "DOMJITPatchpointParams.h"
    3134#include "Disassembler.h"
    3235#include "Exception.h"
     
    7376#include <wtf/CurrentTime.h>
    7477#include <wtf/MainThread.h>
     78#include <wtf/NeverDestroyed.h>
    7579#include <wtf/StringPrintStream.h>
    7680#include <wtf/text/StringBuilder.h>
     
    538542};
    539543
     544class DOMJITNode : public JSNonFinalObject {
     545public:
     546    DOMJITNode(VM& vm, Structure* structure)
     547        : Base(vm, structure)
     548    {
     549    }
     550
     551    DECLARE_INFO;
     552    typedef JSNonFinalObject Base;
     553    static const unsigned StructureFlags = Base::StructureFlags;
     554
     555    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     556    {
     557        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     558    }
     559
     560    static DOMJITNode* create(VM& vm, Structure* structure)
     561    {
     562        DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
     563        getter->finishCreation(vm);
     564        return getter;
     565    }
     566
     567    int32_t value() const
     568    {
     569        return m_value;
     570    }
     571
     572    static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); }
     573
     574private:
     575    int32_t m_value { 42 };
     576};
     577
     578class DOMJITGetter : public DOMJITNode {
     579public:
     580    DOMJITGetter(VM& vm, Structure* structure)
     581        : Base(vm, structure)
     582    {
     583    }
     584
     585    DECLARE_INFO;
     586    typedef DOMJITNode Base;
     587    static const unsigned StructureFlags = Base::StructureFlags;
     588
     589    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     590    {
     591        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     592    }
     593
     594    static DOMJITGetter* create(VM& vm, Structure* structure)
     595    {
     596        DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure);
     597        getter->finishCreation(vm);
     598        return getter;
     599    }
     600
     601    class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
     602    public:
     603        DOMJITNodeDOMJIT()
     604            : DOMJIT::GetterSetter(DOMJITGetter::customGetter, nullptr, DOMJITNode::info())
     605        {
     606        }
     607
     608        Ref<DOMJIT::Patchpoint> checkDOM() override
     609        {
     610            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
     611            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     612                CCallHelpers::JumpList failureCases;
     613                failureCases.append(jit.branch8(
     614                    CCallHelpers::NotEqual,
     615                    CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
     616                    CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
     617                return failureCases;
     618            });
     619            return patchpoint;
     620        }
     621
     622        Ref<DOMJIT::Patchpoint> callDOM() override
     623        {
     624            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
     625            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     626                JSValueRegs results = params[0].jsValueRegs();
     627                GPRReg dom = params[2].gpr();
     628
     629                jit.load32(CCallHelpers::Address(dom, DOMJITNode::offsetOfValue()), results.payloadGPR());
     630                jit.boxInt32(results.payloadGPR(), results);
     631                return CCallHelpers::JumpList();
     632            });
     633            return patchpoint;
     634        }
     635    };
     636
     637    static DOMJIT::GetterSetter* domJITNodeGetterSetter()
     638    {
     639        static NeverDestroyed<DOMJITNodeDOMJIT> graph;
     640        return &graph.get();
     641    }
     642
     643private:
     644    void finishCreation(VM& vm)
     645    {
     646        Base::finishCreation(vm);
     647        DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
     648        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
     649        putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
     650    }
     651
     652    static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     653    {
     654        VM& vm = exec->vm();
     655        auto scope = DECLARE_THROW_SCOPE(vm);
     656
     657        DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
     658        if (!thisObject)
     659            return throwVMTypeError(exec, scope);
     660        return JSValue::encode(jsNumber(thisObject->value()));
     661    }
     662};
    540663
    541664const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
     
    544667const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
    545668const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
     669const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
     670const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
    546671const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
    547672const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
     
    572697static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
    573698static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
     699static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
     700static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
    574701static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
    575702static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
     
    856983        addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
    857984        addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
     985        addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
     986        addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
    858987        addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
    859988        addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
     
    13601489}
    13611490
     1491EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
     1492{
     1493    JSLockHolder lock(exec);
     1494    Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
     1495    DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
     1496    return JSValue::encode(result);
     1497}
     1498
     1499EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
     1500{
     1501    JSLockHolder lock(exec);
     1502    Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
     1503    DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
     1504    return JSValue::encode(result);
     1505}
     1506
    13621507EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
    13631508{
  • trunk/Source/WTF/ChangeLog

    r206811 r206846  
     12016-10-05  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Add initial CheckDOM and CallDOM implementations
     4        https://bugs.webkit.org/show_bug.cgi?id=162941
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * wtf/Box.h:
     9        (WTF::Box::Box):
     10
    1112016-10-05  Zan Dobersek  <zdobersek@igalia.com>
    212
  • trunk/Source/WTF/wtf/Box.h

    r193890 r206846  
    4141    }
    4242
     43    Box(std::nullptr_t)
     44    {
     45    }
     46
    4347    template<typename... Arguments>
    4448    static Box create(Arguments&&... arguments)
Note: See TracChangeset for help on using the changeset viewer.