Changeset 207427 in webkit


Ignore:
Timestamp:
Oct 17, 2016 1:43:43 PM (7 years ago)
Author:
Yusuke Suzuki
Message:

[DOMJIT] Use DOMJIT::Patchpoint in IC
https://bugs.webkit.org/show_bug.cgi?id=163223

Reviewed by Saam Barati.

JSTests:

  • stress/domjit-exception-ic.js: Added.

(shouldBe):
(access):

  • stress/domjit-exception.js: Added.

(shouldBe):
(access):

  • stress/domjit-getter-complex-with-incorrect-object.js: Added.

(shouldThrow):
(access):
(i.shouldThrow):

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

(shouldBe):
(access):

  • stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js: Added.

(assert):
(bar):
(foo):

Source/JavaScriptCore:

This patch uses DOMJIT::Patchpoint to inline DOM accesses even in IC!
It is useful for Baseline JIT cases and GetById cases in DFG and FTL.
In AccessCase, we construct the environment that allows DOMJIT::Patchpoint
to emit code and make DOMJIT accessors inlined in IC.

To allow DOMJIT::Patchpoint to emit code, we create a mechanism to emit calls
required in DOMJIT::Patchpoint. This system is useful when we create the super-
polymorphic support[1] later. And inlining mechanism is useful even after
introducing super-polymorphic support since it can work even after we fire the
watchpoint for super-polymorphic handling.

This patch improves Dromaeo dom-traverse 8% (263.95 runs/s v.s. 244.07 runs/s).

[1]: https://bugs.webkit.org/show_bug.cgi?id=163226

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.

(JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
(JSC::SlowPathCallGeneratorWithArguments::generateImpl):
(JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):

  • bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h.

(JSC::DOMJITAccessCasePatchpointParams::DOMJITAccessCasePatchpointParams):
(JSC::DOMJITAccessCasePatchpointParams::SlowPathCallGenerator::~SlowPathCallGenerator):

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessGenerationState::liveRegistersForCall):
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
(JSC::calleeSaveRegisters):
(JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
(JSC::AccessGenerationState::originalExceptionHandler):
(JSC::AccessCase::generateImpl):
(JSC::AccessCase::emitDOMJITGetter):
(JSC::PolymorphicAccess::regenerate):
(JSC::AccessGenerationState::preserveLiveRegistersToStackForCall): Deleted.

  • bytecode/PolymorphicAccess.h:

(JSC::AccessGenerationState::SpillState::isEmpty):
(JSC::AccessGenerationState::setSpillStateForJSGetterSetter):
(JSC::AccessGenerationState::spillStateForJSGetterSetter):
(JSC::AccessGenerationState::liveRegistersForCall): Deleted.
(JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation): Deleted.
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite): Deleted.

  • dfg/DFGDOMJITPatchpointParams.cpp:
  • dfg/DFGDOMJITPatchpointParams.h:
  • domjit/DOMJITPatchpoint.h:
  • domjit/DOMJITPatchpointParams.h:

(JSC::DOMJIT::PatchpointParams::addSlowPathCall):

  • ftl/FTLDOMJITPatchpointParams.cpp:
  • ftl/FTLDOMJITPatchpointParams.h:
  • jsc.cpp:

(WTF::DOMJITNode::checkDOMJITNode):
(WTF::DOMJITGetterComplex::DOMJITGetterComplex):
(WTF::DOMJITGetterComplex::createStructure):
(WTF::DOMJITGetterComplex::create):
(WTF::DOMJITGetterComplex::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
(WTF::DOMJITGetterComplex::domJITNodeGetterSetter):
(WTF::DOMJITGetterComplex::finishCreation):
(WTF::DOMJITGetterComplex::functionEnableException):
(WTF::DOMJITGetterComplex::customGetter):
(GlobalObject::finishCreation):
(functionCreateDOMJITGetterComplexObject):

Source/WebCore:

Make DOMJITPatchpointParams non-const.

  • domjit/DOMJITHelpers.h:

(WebCore::DOMJITHelpers::toWrapper):

  • domjit/JSNodeDOMJIT.cpp:

(WebCore::createCallDOMForOffsetAccess):
(WebCore::checkNode):
(WebCore::NodeNodeTypeDOMJIT::callDOM):

Location:
trunk
Files:
6 added
16 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r207377 r207427  
     12016-10-17  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Use DOMJIT::Patchpoint in IC
     4        https://bugs.webkit.org/show_bug.cgi?id=163223
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/domjit-exception-ic.js: Added.
     9        (shouldBe):
     10        (access):
     11        * stress/domjit-exception.js: Added.
     12        (shouldBe):
     13        (access):
     14        * stress/domjit-getter-complex-with-incorrect-object.js: Added.
     15        (shouldThrow):
     16        (access):
     17        (i.shouldThrow):
     18        * stress/domjit-getter-complex.js: Added.
     19        (shouldBe):
     20        (access):
     21        * stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js: Added.
     22        (assert):
     23        (bar):
     24        (foo):
     25
    1262016-10-15  Saam Barati  <sbarati@apple.com>
    227
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r207360 r207427  
    205205    bytecode/DataFormat.cpp
    206206    bytecode/DFGExitProfile.cpp
     207    bytecode/DOMJITAccessCasePatchpointParams.cpp
    207208    bytecode/DeferredCompilationCallback.cpp
    208209    bytecode/DeferredSourceDump.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r207425 r207427  
     12016-10-17  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Use DOMJIT::Patchpoint in IC
     4        https://bugs.webkit.org/show_bug.cgi?id=163223
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch uses DOMJIT::Patchpoint to inline DOM accesses even in IC!
     9        It is useful for Baseline JIT cases and GetById cases in DFG and FTL.
     10        In AccessCase, we construct the environment that allows DOMJIT::Patchpoint
     11        to emit code and make DOMJIT accessors inlined in IC.
     12
     13        To allow DOMJIT::Patchpoint to emit code, we create a mechanism to emit calls
     14        required in DOMJIT::Patchpoint. This system is useful when we create the super-
     15        polymorphic support[1] later. And inlining mechanism is useful even after
     16        introducing super-polymorphic support since it can work even after we fire the
     17        watchpoint for super-polymorphic handling.
     18
     19        This patch improves Dromaeo dom-traverse 8% (263.95 runs/s v.s. 244.07 runs/s).
     20
     21        [1]: https://bugs.webkit.org/show_bug.cgi?id=163226
     22
     23        * CMakeLists.txt:
     24        * JavaScriptCore.xcodeproj/project.pbxproj:
     25        * bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.
     26        (JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
     27        (JSC::SlowPathCallGeneratorWithArguments::generateImpl):
     28        (JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):
     29        * bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h.
     30        (JSC::DOMJITAccessCasePatchpointParams::DOMJITAccessCasePatchpointParams):
     31        (JSC::DOMJITAccessCasePatchpointParams::SlowPathCallGenerator::~SlowPathCallGenerator):
     32        * bytecode/PolymorphicAccess.cpp:
     33        (JSC::AccessGenerationState::liveRegistersForCall):
     34        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
     35        (JSC::calleeSaveRegisters):
     36        (JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
     37        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
     38        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
     39        (JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
     40        (JSC::AccessGenerationState::originalExceptionHandler):
     41        (JSC::AccessCase::generateImpl):
     42        (JSC::AccessCase::emitDOMJITGetter):
     43        (JSC::PolymorphicAccess::regenerate):
     44        (JSC::AccessGenerationState::preserveLiveRegistersToStackForCall): Deleted.
     45        * bytecode/PolymorphicAccess.h:
     46        (JSC::AccessGenerationState::SpillState::isEmpty):
     47        (JSC::AccessGenerationState::setSpillStateForJSGetterSetter):
     48        (JSC::AccessGenerationState::spillStateForJSGetterSetter):
     49        (JSC::AccessGenerationState::liveRegistersForCall): Deleted.
     50        (JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation): Deleted.
     51        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite): Deleted.
     52        * dfg/DFGDOMJITPatchpointParams.cpp:
     53        * dfg/DFGDOMJITPatchpointParams.h:
     54        * domjit/DOMJITPatchpoint.h:
     55        * domjit/DOMJITPatchpointParams.h:
     56        (JSC::DOMJIT::PatchpointParams::addSlowPathCall):
     57        * ftl/FTLDOMJITPatchpointParams.cpp:
     58        * ftl/FTLDOMJITPatchpointParams.h:
     59        * jsc.cpp:
     60        (WTF::DOMJITNode::checkDOMJITNode):
     61        (WTF::DOMJITGetterComplex::DOMJITGetterComplex):
     62        (WTF::DOMJITGetterComplex::createStructure):
     63        (WTF::DOMJITGetterComplex::create):
     64        (WTF::DOMJITGetterComplex::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
     65        (WTF::DOMJITGetterComplex::domJITNodeGetterSetter):
     66        (WTF::DOMJITGetterComplex::finishCreation):
     67        (WTF::DOMJITGetterComplex::functionEnableException):
     68        (WTF::DOMJITGetterComplex::customGetter):
     69        (GlobalObject::finishCreation):
     70        (functionCreateDOMJITGetterComplexObject):
     71
    1722016-10-17  Saam Barati  <sbarati@apple.com>
    273
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r207360 r207427  
    21152115                E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21162116                E3A421431D6F58930007C617 /* PreciseJumpTargetsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2117                E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */; };
     2118                E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */; };
    21172119                E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21182120                E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */; };
     
    44244426                E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; };
    44254427                E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargetsInlines.h; sourceTree = "<group>"; };
     4428                E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAccessCasePatchpointParams.cpp; sourceTree = "<group>"; };
     4429                E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAccessCasePatchpointParams.h; sourceTree = "<group>"; };
    44264430                E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpoint.h; sourceTree = "<group>"; };
    44274431                E3CB1E241DA7540A00FA1E56 /* DOMJITSlowPathCalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSlowPathCalls.h; sourceTree = "<group>"; };
     
    68256829                                0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */,
    68266830                                0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */,
     6831                                E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */,
     6832                                E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */,
    68276833                                62E3D5EF1B8D0B7300B868BB /* DataFormat.cpp */,
    68286834                                0F426A4A1460CD6B00131F8F /* DataFormat.h */,
     
    75277533                                86EC9DC51328DF82002B2AD7 /* DFGByteCodeParser.h in Headers */,
    75287534                                0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */,
     7535                                E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */,
    75297536                                0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */,
    75307537                                0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */,
     
    94239430                                A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */,
    94249431                                A50E4B6118809DD50068A46D /* InspectorRuntimeAgent.cpp in Sources */,
     9432                                E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */,
    94259433                                A593CF821840377100BFCE27 /* InspectorValues.cpp in Sources */,
    94269434                                147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */,
  • trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.h

    r207426 r207427  
    2626#pragma once
    2727
    28 #if ENABLE(FTL_JIT)
     28#if ENABLE(JIT)
    2929
    30 #include "B3StackmapGenerationParams.h"
    3130#include "DOMJITPatchpointParams.h"
    3231
    33 namespace JSC { namespace FTL {
     32namespace JSC {
    3433
    35 class State;
     34struct AccessGenerationState;
    3635
    37 class DOMJITPatchpointParams : public DOMJIT::PatchpointParams {
     36class DOMJITAccessCasePatchpointParams : public DOMJIT::PatchpointParams {
    3837public:
    39     DOMJITPatchpointParams(State& state, const B3::StackmapGenerationParams& params, DFG::Node* node, Box<CCallHelpers::JumpList> exceptions, Vector<DOMJIT::Value>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
     38    DOMJITAccessCasePatchpointParams(Vector<DOMJIT::Value>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
    4039        : DOMJIT::PatchpointParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch))
    41         , m_state(state)
    42         , m_params(params)
    43         , m_node(node)
    44         , m_exceptions(exceptions)
    4540    {
    4641    }
    4742
     43    class SlowPathCallGenerator {
     44    public:
     45        virtual ~SlowPathCallGenerator() { }
     46        virtual CCallHelpers::JumpList generate(VM&, AccessGenerationState&, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers&) = 0;
     47    };
     48
     49    CCallHelpers::JumpList emitSlowPathCalls(VM&, AccessGenerationState&, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers&);
     50
    4851private:
    49 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const override;
     52#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
    5053    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
    5154#undef JSC_DEFINE_CALL_OPERATIONS
    52 
    53     State& m_state;
    54     const B3::StackmapGenerationParams& m_params;
    55     DFG::Node* m_node;
    56     Box<CCallHelpers::JumpList> m_exceptions;
     55    Vector<std::unique_ptr<SlowPathCallGenerator>> m_generators;
    5756};
    5857
    59 } }
     58}
    6059
    6160#endif
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp

    r206779 r207427  
    3232#include "CCallHelpers.h"
    3333#include "CodeBlock.h"
     34#include "DOMJITAccessCasePatchpointParams.h"
     35#include "DOMJITCallDOMPatchpoint.h"
    3436#include "DirectArguments.h"
    3537#include "GetterSetter.h"
     
    7375}
    7476
    75 void AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra)
     77const RegisterSet& AccessGenerationState::liveRegistersForCall()
     78{
     79    if (!m_calculatedRegistersForCallAndExceptionHandling)
     80        calculateLiveRegistersForCallAndExceptionHandling();
     81    return m_liveRegistersForCall;
     82}
     83
     84const RegisterSet& AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite()
     85{
     86    if (!m_calculatedRegistersForCallAndExceptionHandling)
     87        calculateLiveRegistersForCallAndExceptionHandling();
     88    return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
     89}
     90
     91static RegisterSet calleeSaveRegisters()
     92{
     93    RegisterSet result = RegisterSet::registersToNotSaveForJSCall();
     94    result.filter(RegisterSet::registersToNotSaveForCCall());
     95    return result;
     96}
     97
     98const RegisterSet& AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling()
    7699{
    77100    if (!m_calculatedRegistersForCallAndExceptionHandling) {
     
    84107
    85108        m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator->usedRegisters());
    86         m_liveRegistersForCall.merge(extra);
    87         m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForJSCall());
    88         m_liveRegistersForCall.merge(extra);
    89     }
    90 }
    91 
    92 void AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet& extra)
    93 {
    94     calculateLiveRegistersForCallAndExceptionHandling(extra);
     109        m_liveRegistersForCall.exclude(calleeSaveRegisters());
     110    }
     111    return m_liveRegistersForCall;
     112}
     113
     114auto AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet& extra) -> SpillState
     115{
     116    RegisterSet liveRegisters = liveRegistersForCall();
     117    liveRegisters.merge(extra);
    95118   
    96119    unsigned extraStackPadding = 0;
    97     unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
    98     if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits<unsigned>::max())
    99         RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
    100     m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
    101 }
    102 
    103 void AccessGenerationState::restoreLiveRegistersFromStackForCall(bool isGetter)
    104 {
    105     RegisterSet dontRestore;
    106     if (isGetter) {
    107         // This is the result value. We don't want to overwrite the result with what we stored to the stack.
    108         // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
    109         dontRestore.set(valueRegs);
    110     }
    111     restoreLiveRegistersFromStackForCall(dontRestore);
    112 }
    113 
    114 void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException()
     120    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegisters, extraStackPadding);
     121    return SpillState {
     122        liveRegisters,
     123        numberOfStackBytesUsedForRegisterPreservation
     124    };
     125}
     126
     127void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException(const SpillState& spillState)
    115128{
    116129    // Even if we're a getter, we don't want to ignore the result value like we normally do
     
    120133    // and the getter threw, we want OSR exit to see the original base value, not the result
    121134    // of the getter call.
    122     RegisterSet dontRestore = liveRegistersForCall();
     135    RegisterSet dontRestore = spillState.spilledRegisters;
    123136    // As an optimization here, we only need to restore what is live for exception handling.
    124137    // We can construct the dontRestore set to accomplish this goal by having it contain only
     
    127140    // at the exception handler.
    128141    dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
    129     restoreLiveRegistersFromStackForCall(dontRestore);
    130 }
    131 
    132 void AccessGenerationState::restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore)
     142    restoreLiveRegistersFromStackForCall(spillState, dontRestore);
     143}
     144
     145void AccessGenerationState::restoreLiveRegistersFromStackForCall(const SpillState& spillState, const RegisterSet& dontRestore)
    133146{
    134147    unsigned extraStackPadding = 0;
    135     ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
     148    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, spillState.spilledRegisters, dontRestore, spillState.numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
    136149}
    137150
    138151CallSiteIndex AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal()
    139152{
    140     RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
     153    if (!m_calculatedRegistersForCallAndExceptionHandling)
     154        calculateLiveRegistersForCallAndExceptionHandling();
    141155
    142156    if (!m_calculatedCallSiteIndex) {
     
    152166}
    153167
    154 const HandlerInfo& AccessGenerationState::originalExceptionHandler() const
    155 {
     168const HandlerInfo& AccessGenerationState::originalExceptionHandler()
     169{
     170    if (!m_calculatedRegistersForCallAndExceptionHandling)
     171        calculateLiveRegistersForCallAndExceptionHandling();
     172
    156173    RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
    157174    HandlerInfo* exceptionHandler = jit->codeBlock()->handlerForIndex(stubInfo->callSiteIndex.bits());
     
    933950        }
    934951
     952        if (m_type == CustomAccessorGetter && m_rareData->domJIT) {
     953            // We do not need to emit CheckDOM operation since structure check ensures
     954            // that the structure of the given base value is structure()! So all we should
     955            // do is performing the CheckDOM thingy in IC compiling time here.
     956            if (structure()->classInfo()->isSubClassOf(m_rareData->domJIT->thisClassInfo())) {
     957                emitDOMJITGetter(state, baseForGetGPR);
     958                return;
     959            }
     960        }
     961
    935962        // Stuff for custom getters/setters.
    936963        CCallHelpers::Call operationCall;
     
    941968        CCallHelpers::Call slowPathCall;
    942969
    943         CCallHelpers::Jump success;
    944         CCallHelpers::Jump fail;
    945 
    946970        // This also does the necessary calculations of whether or not we're an
    947971        // exception handling call site.
    948         state.preserveLiveRegistersToStackForCall();
     972        AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall();
     973
     974        auto restoreLiveRegistersFromStackForCall = [&](AccessGenerationState::SpillState& spillState, bool callHasReturnValue) {
     975            RegisterSet dontRestore;
     976            if (callHasReturnValue) {
     977                // This is the result value. We don't want to overwrite the result with what we stored to the stack.
     978                // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
     979                dontRestore.set(valueRegs);
     980            }
     981            state.restoreLiveRegistersFromStackForCall(spillState, dontRestore);
     982        };
    949983
    950984        jit.store32(
     
    9661000            // Therefore, we temporarily grow the stack for the purpose of the call and then
    9671001            // shrink it after.
     1002
     1003            state.setSpillStateForJSGetterSetter(spillState);
    9681004
    9691005            RELEASE_ASSERT(!m_rareData->callLinkInfo);
     
    10661102            done.link(&jit);
    10671103
    1068             jit.addPtr(CCallHelpers::TrustedImm32((codeBlock->stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - state.numberOfStackBytesUsedForRegisterPreservation()),
     1104            jit.addPtr(CCallHelpers::TrustedImm32((codeBlock->stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - spillState.numberOfStackBytesUsedForRegisterPreservation),
    10691105                GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
    1070             state.restoreLiveRegistersFromStackForCall(isGetter());
     1106            bool callHasReturnValue = isGetter();
     1107            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
    10711108
    10721109            jit.addLinkTask(
     
    11281165                jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
    11291166
    1130             state.restoreLiveRegistersFromStackForCallWithThrownException();
     1167            state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
    11311168            state.emitExplicitExceptionHandler();
    11321169       
    11331170            noException.link(&jit);
    1134             state.restoreLiveRegistersFromStackForCall(isGetter());
     1171            bool callHasReturnValue = isGetter();
     1172            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
    11351173        }
    11361174        state.succeed();
     
    12491287                extraRegistersToPreserve.set(baseGPR);
    12501288                extraRegistersToPreserve.set(valueRegs);
    1251                 state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
     1289                AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
    12521290               
    12531291                jit.store32(
     
    12891327                    jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
    12901328               
    1291                 state.restoreLiveRegistersFromStackForCallWithThrownException();
     1329                state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
    12921330                state.emitExplicitExceptionHandler();
    12931331               
    12941332                noException.link(&jit);
    1295                 state.restoreLiveRegistersFromStackForCall();
     1333                state.restoreLiveRegistersFromStackForCall(spillState);
    12961334            }
    12971335        }
     
    13861424}
    13871425
     1426void AccessCase::emitDOMJITGetter(AccessGenerationState& state, GPRReg baseForGetGPR)
     1427{
     1428    CCallHelpers& jit = *state.jit;
     1429    VM& vm = *jit.vm();
     1430    StructureStubInfo& stubInfo = *state.stubInfo;
     1431    JSValueRegs valueRegs = state.valueRegs;
     1432    GPRReg baseGPR = state.baseGPR;
     1433    GPRReg scratchGPR = state.scratchGPR;
     1434
     1435    // We construct the environment that can execute the DOMJIT::Patchpoint here.
     1436    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = m_rareData->domJIT->callDOM();
     1437
     1438    Vector<GPRReg> gpScratch;
     1439    Vector<FPRReg> fpScratch;
     1440    Vector<DOMJIT::Value> regs;
     1441
     1442    ScratchRegisterAllocator allocator(stubInfo.patch.usedRegisters);
     1443    allocator.lock(baseGPR);
     1444#if USE(JSVALUE32_64)
     1445    allocator.lock(static_cast<GPRReg>(stubInfo.patch.baseTagGPR));
     1446#endif
     1447    allocator.lock(valueRegs);
     1448    allocator.lock(scratchGPR);
     1449
     1450    GPRReg paramBaseGPR = InvalidGPRReg;
     1451    GPRReg paramGlobalObjectGPR = InvalidGPRReg;
     1452    JSValueRegs paramValueRegs = valueRegs;
     1453    GPRReg remainingScratchGPR = InvalidGPRReg;
     1454
     1455    // valueRegs and baseForGetGPR may be the same. For example, in Baseline JIT, we pass the same regT0 for baseGPR and valueRegs.
     1456    // In FTL, there is no constraint that the baseForGetGPR interferes with the result. To make implementation simple in
     1457    // DOMJIT::Patchpoint, DOMJIT::Patchpoint assumes that result registers always early interfere with input registers, in this case,
     1458    // baseForGetGPR. So we move baseForGetGPR to the other register if baseForGetGPR == valueRegs.
     1459    if (baseForGetGPR != valueRegs.payloadGPR()) {
     1460        paramBaseGPR = baseForGetGPR;
     1461        if (!patchpoint->requireGlobalObject)
     1462            remainingScratchGPR = scratchGPR;
     1463        else
     1464            paramGlobalObjectGPR = scratchGPR;
     1465    } else {
     1466        jit.move(valueRegs.payloadGPR(), scratchGPR);
     1467        paramBaseGPR = scratchGPR;
     1468        if (patchpoint->requireGlobalObject)
     1469            paramGlobalObjectGPR = allocator.allocateScratchGPR();
     1470    }
     1471
     1472    JSGlobalObject* globalObjectForDOMJIT = structure()->globalObject();
     1473
     1474    regs.append(paramValueRegs);
     1475    if (patchpoint->requireGlobalObject) {
     1476        ASSERT(paramGlobalObjectGPR != InvalidGPRReg);
     1477        regs.append(DOMJIT::Value(paramGlobalObjectGPR, globalObjectForDOMJIT));
     1478    }
     1479    regs.append(paramBaseGPR);
     1480
     1481    if (patchpoint->numGPScratchRegisters) {
     1482        unsigned i = 0;
     1483        if (remainingScratchGPR != InvalidGPRReg) {
     1484            gpScratch.append(remainingScratchGPR);
     1485            ++i;
     1486        }
     1487        for (; i < patchpoint->numGPScratchRegisters; ++i)
     1488            gpScratch.append(allocator.allocateScratchGPR());
     1489    }
     1490
     1491    for (unsigned i = 0; i < patchpoint->numFPScratchRegisters; ++i)
     1492        fpScratch.append(allocator.allocateScratchFPR());
     1493
     1494    // Let's store the reused registers to the stack. After that, we can use allocated scratch registers.
     1495    ScratchRegisterAllocator::PreservedState preservedState =
     1496        allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
     1497
     1498    if (verbose) {
     1499        dataLog("baseGPR = ", baseGPR, "\n");
     1500        dataLog("valueRegs = ", valueRegs, "\n");
     1501        dataLog("scratchGPR = ", scratchGPR, "\n");
     1502        dataLog("paramBaseGPR = ", paramBaseGPR, "\n");
     1503        if (paramGlobalObjectGPR != InvalidGPRReg)
     1504            dataLog("paramGlobalObjectGPR = ", paramGlobalObjectGPR, "\n");
     1505        dataLog("paramValueRegs = ", paramValueRegs, "\n");
     1506        for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
     1507            dataLog("gpScratch[", i, "] = ", gpScratch[i], "\n");
     1508    }
     1509
     1510    if (patchpoint->requireGlobalObject)
     1511        jit.move(CCallHelpers::TrustedImmPtr(globalObjectForDOMJIT), paramGlobalObjectGPR);
     1512
     1513    // We just spill the registers used in DOMJIT::Patchpoint here. For not spilled registers here explicitly,
     1514    // they must be in the used register set passed by the callers (Baseline, DFG, and FTL) if they need to be kept.
     1515    // Some registers can be locked, but not in the used register set. For example, the caller could make baseGPR
     1516    // same to valueRegs, and not include it in the used registers since it will be changed.
     1517    RegisterSet registersToSpillForCCall;
     1518    for (auto& value : regs) {
     1519        DOMJIT::Reg reg = value.reg();
     1520        if (reg.isJSValueRegs())
     1521            registersToSpillForCCall.set(reg.jsValueRegs());
     1522        else if (reg.isGPR())
     1523            registersToSpillForCCall.set(reg.gpr());
     1524        else
     1525            registersToSpillForCCall.set(reg.fpr());
     1526    }
     1527    for (GPRReg reg : gpScratch)
     1528        registersToSpillForCCall.set(reg);
     1529    for (FPRReg reg : fpScratch)
     1530        registersToSpillForCCall.set(reg);
     1531    registersToSpillForCCall.exclude(RegisterSet::registersToNotSaveForCCall());
     1532
     1533    DOMJITAccessCasePatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     1534    patchpoint->generator()->run(jit, params);
     1535    allocator.restoreReusedRegistersByPopping(jit, preservedState);
     1536    state.succeed();
     1537
     1538    CCallHelpers::JumpList exceptions = params.emitSlowPathCalls(vm, state, registersToSpillForCCall, jit);
     1539    exceptions.link(&jit);
     1540    allocator.restoreReusedRegistersByPopping(jit, preservedState);
     1541    state.emitExplicitExceptionHandler();
     1542}
     1543
    13881544PolymorphicAccess::PolymorphicAccess() { }
    13891545PolymorphicAccess::~PolymorphicAccess() { }
     
    16851841
    16861842        int stackPointerOffset = codeBlock->stackPointerOffset() * sizeof(EncodedJSValue);
     1843        AccessGenerationState::SpillState spillStateForJSGetterSetter = state.spillStateForJSGetterSetter();
     1844        ASSERT(!spillStateForJSGetterSetter.isEmpty());
    16871845        stackPointerOffset -= state.preservedReusedRegisterState.numberOfBytesPreserved;
    1688         stackPointerOffset -= state.numberOfStackBytesUsedForRegisterPreservation();
     1846        stackPointerOffset -= spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation;
    16891847
    16901848        jit.loadPtr(vm.addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
    16911849        jit.addPtr(CCallHelpers::TrustedImm32(stackPointerOffset), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
    16921850
    1693         state.restoreLiveRegistersFromStackForCallWithThrownException();
     1851        state.restoreLiveRegistersFromStackForCallWithThrownException(spillStateForJSGetterSetter);
    16941852        state.restoreScratch();
    16951853        CCallHelpers::Jump jumpToOSRExitExceptionHandler = jit.jump();
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h

    r206779 r207427  
    278278    void generateImpl(AccessGenerationState&);
    279279    void emitIntrinsicGetter(AccessGenerationState&);
     280    void emitDOMJITGetter(AccessGenerationState&, GPRReg baseForGetGPR);
    280281   
    281282    AccessType m_type { Load };
     
    473474    void succeed();
    474475
    475     void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
    476 
    477     void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
    478 
    479     void restoreLiveRegistersFromStackForCall(bool isGetter = false);
    480     void restoreLiveRegistersFromStackForCallWithThrownException();
    481     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
    482 
    483     const RegisterSet& liveRegistersForCall()
    484     {
    485         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    486         return m_liveRegistersForCall;
    487     }
     476    struct SpillState {
     477        RegisterSet spilledRegisters { };
     478        unsigned numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
     479
     480        bool isEmpty() const { return numberOfStackBytesUsedForRegisterPreservation == std::numeric_limits<unsigned>::max(); }
     481    };
     482
     483    const RegisterSet& calculateLiveRegistersForCallAndExceptionHandling();
     484
     485    SpillState preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
     486
     487    void restoreLiveRegistersFromStackForCallWithThrownException(const SpillState&);
     488    void restoreLiveRegistersFromStackForCall(const SpillState&, const RegisterSet& dontRestore = RegisterSet());
     489
     490    const RegisterSet& liveRegistersForCall();
    488491
    489492    CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
     
    496499    }
    497500
    498     const HandlerInfo& originalExceptionHandler() const;
    499     unsigned numberOfStackBytesUsedForRegisterPreservation() const
    500     {
    501         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    502         return m_numberOfStackBytesUsedForRegisterPreservation;
    503     }
     501    const HandlerInfo& originalExceptionHandler();
    504502
    505503    bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
     
    507505   
    508506    void emitExplicitExceptionHandler();
     507
     508    void setSpillStateForJSGetterSetter(SpillState& spillState)
     509    {
     510        if (!m_spillStateForJSGetterSetter.isEmpty()) {
     511            ASSERT(m_spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation == spillState.numberOfStackBytesUsedForRegisterPreservation);
     512            ASSERT(m_spillStateForJSGetterSetter.spilledRegisters == spillState.spilledRegisters);
     513        }
     514        m_spillStateForJSGetterSetter = spillState;
     515    }
     516    SpillState spillStateForJSGetterSetter() const { return m_spillStateForJSGetterSetter; }
    509517   
    510518private:
    511     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
    512     {
    513         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
    514         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
    515     }
     519    const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite();
    516520   
    517521    RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
    518522    RegisterSet m_liveRegistersForCall;
    519523    CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
    520     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
     524    SpillState m_spillStateForJSGetterSetter;
    521525    bool m_calculatedRegistersForCallAndExceptionHandling : 1;
    522526    bool m_needsToRestoreRegistersIfException : 1;
  • trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.cpp

    r206899 r207427  
    4141
    4242#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
    43     void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) const \
     43    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \
    4444    { \
    4545        dispatch(m_jit, from, operation, result, args, std::make_index_sequence<std::tuple_size<decltype(args)>::value>()); \
  • trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.h

    r207166 r207427  
    4343
    4444private:
    45 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const override;
     45#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
    4646    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
    4747#undef JSC_DEFINE_CALL_OPERATIONS
  • trunk/Source/JavaScriptCore/domjit/DOMJITPatchpoint.h

    r207239 r207427  
    3535class PatchpointParams;
    3636
    37 typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&, const PatchpointParams&);
     37typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&, PatchpointParams&);
    3838typedef SharedTask<PatchpointGeneratorFunction> PatchpointGenerator;
    3939
  • trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h

    r207166 r207427  
    5656
    5757    template<typename FunctionType, typename ResultType, typename... Arguments>
    58     void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers& jit, FunctionType function, ResultType result, Arguments... arguments) const
     58    void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers& jit, FunctionType function, ResultType result, Arguments... arguments)
    5959    {
    6060        addSlowPathCallImpl(from, jit, function, result, std::make_tuple(arguments...));
     
    6262
    6363private:
    64 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const = 0;
     64#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) = 0;
    6565    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
    6666#undef JSC_DEFINE_CALL_OPERATIONS
  • trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.cpp

    r206899 r207427  
    5151
    5252#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
    53     void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) const \
     53    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \
    5454    { \
    5555        dispatch(jit, &m_state, m_params, m_node, m_exceptions, from, operation, result, args, std::make_index_sequence<std::tuple_size<decltype(args)>::value>()); \
  • trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h

    r207166 r207427  
    4747
    4848private:
    49 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const override;
     49#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
    5050    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
    5151#undef JSC_DEFINE_CALL_OPERATIONS
  • trunk/Source/JavaScriptCore/jsc.cpp

    r207377 r207427  
    558558    }
    559559
     560#if ENABLE(JIT)
     561    static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
     562    {
     563        Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
     564        patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
     565            CCallHelpers::JumpList failureCases;
     566            failureCases.append(jit.branch8(
     567                CCallHelpers::NotEqual,
     568                CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
     569                CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
     570            return failureCases;
     571        });
     572        return patchpoint;
     573    }
     574#endif
     575
    560576    static DOMJITNode* create(VM& vm, Structure* structure)
    561577    {
     
    609625        Ref<DOMJIT::Patchpoint> checkDOM() override
    610626        {
    611             Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
    612             patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
    613                 CCallHelpers::JumpList failureCases;
    614                 failureCases.append(jit.branch8(
    615                     CCallHelpers::NotEqual,
    616                     CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
    617                     CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
    618                 return failureCases;
    619             });
    620             return patchpoint;
     627            return DOMJITNode::checkDOMJITNode();
    621628        }
    622629
     
    625632            Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
    626633            patchpoint->requireGlobalObject = false;
    627             patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     634            patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
    628635                JSValueRegs results = params[0].jsValueRegs();
    629636                GPRReg dom = params[1].gpr();
     
    665672        return JSValue::encode(jsNumber(thisObject->value()));
    666673    }
     674};
     675
     676class DOMJITGetterComplex : public DOMJITNode {
     677public:
     678    DOMJITGetterComplex(VM& vm, Structure* structure)
     679        : Base(vm, structure)
     680    {
     681    }
     682
     683    DECLARE_INFO;
     684    typedef DOMJITNode Base;
     685    static const unsigned StructureFlags = Base::StructureFlags;
     686
     687    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     688    {
     689        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     690    }
     691
     692    static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     693    {
     694        DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure);
     695        getter->finishCreation(vm, globalObject);
     696        return getter;
     697    }
     698
     699    class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
     700    public:
     701        DOMJITNodeDOMJIT()
     702            : DOMJIT::GetterSetter(DOMJITGetterComplex::customGetter, nullptr, DOMJITNode::info())
     703        {
     704        }
     705
     706#if ENABLE(JIT)
     707        Ref<DOMJIT::Patchpoint> checkDOM() override
     708        {
     709            return DOMJITNode::checkDOMJITNode();
     710        }
     711
     712        Ref<DOMJIT::CallDOMPatchpoint> callDOM() override
     713        {
     714            RefPtr<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
     715            static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4.");
     716            patchpoint->numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
     717            patchpoint->numFPScratchRegisters = 3;
     718            patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
     719                JSValueRegs results = params[0].jsValueRegs();
     720                GPRReg domGPR = params[2].gpr();
     721                for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
     722                    jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
     723
     724                params.addSlowPathCall(jit.jump(), jit, static_cast<EncodedJSValue(*)(ExecState*, void*)>([](ExecState* exec, void* pointer) {
     725                    VM& vm = exec->vm();
     726                    auto scope = DECLARE_THROW_SCOPE(vm);
     727                    auto* object = static_cast<DOMJITNode*>(pointer);
     728                    auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(object);
     729                    if (domjitGetterComplex) {
     730                        if (domjitGetterComplex->m_enableException)
     731                            return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
     732                    }
     733                    return JSValue::encode(jsNumber(object->value()));
     734                }), results, domGPR);
     735                return CCallHelpers::JumpList();
     736
     737            });
     738            return *patchpoint.get();
     739        }
     740#endif
     741    };
     742
     743    static DOMJIT::GetterSetter* domJITNodeGetterSetter()
     744    {
     745        static NeverDestroyed<DOMJITNodeDOMJIT> graph;
     746        return &graph.get();
     747    }
     748
     749private:
     750    void finishCreation(VM& vm, JSGlobalObject* globalObject)
     751    {
     752        Base::finishCreation(vm);
     753        DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
     754        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
     755        putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
     756        putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "enableException"), 0, functionEnableException, NoIntrinsic, 0);
     757    }
     758
     759    static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
     760    {
     761        auto* object = jsDynamicCast<DOMJITGetterComplex*>(exec->thisValue());
     762        if (object)
     763            object->m_enableException = true;
     764        return JSValue::encode(jsUndefined());
     765    }
     766
     767    static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     768    {
     769        VM& vm = exec->vm();
     770        auto scope = DECLARE_THROW_SCOPE(vm);
     771
     772        auto* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
     773        if (!thisObject)
     774            return throwVMTypeError(exec, scope);
     775        if (auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(JSValue::decode(thisValue))) {
     776            if (domjitGetterComplex->m_enableException)
     777                return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
     778        }
     779        return JSValue::encode(jsNumber(thisObject->value()));
     780    }
     781
     782    bool m_enableException { false };
    667783};
    668784
     
    674790const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
    675791const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
     792const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetterComplex) };
    676793const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
    677794const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
     
    704821static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
    705822static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
     823static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState*);
    706824static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
    707825static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
     
    9911109        addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
    9921110        addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
     1111        addFunction(vm, "createDOMJITGetterComplexObject", functionCreateDOMJITGetterComplexObject, 0);
    9931112        addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
    9941113        addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
     
    15121631}
    15131632
     1633EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
     1634{
     1635    JSLockHolder lock(exec);
     1636    Structure* structure = DOMJITGetterComplex::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
     1637    DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec->vm(), exec->lexicalGlobalObject(), structure);
     1638    return JSValue::encode(result);
     1639}
     1640
    15141641EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
    15151642{
  • trunk/Source/WebCore/ChangeLog

    r207426 r207427  
     12016-10-17  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [DOMJIT] Use DOMJIT::Patchpoint in IC
     4        https://bugs.webkit.org/show_bug.cgi?id=163223
     5
     6        Reviewed by Saam Barati.
     7
     8        Make DOMJITPatchpointParams non-const.
     9
     10        * domjit/DOMJITHelpers.h:
     11        (WebCore::DOMJITHelpers::toWrapper):
     12        * domjit/JSNodeDOMJIT.cpp:
     13        (WebCore::createCallDOMForOffsetAccess):
     14        (WebCore::checkNode):
     15        (WebCore::NodeNodeTypeDOMJIT::callDOM):
     16
    1172016-10-17  Chris Dumez  <cdumez@apple.com>
    218
  • trunk/Source/WebCore/domjit/DOMJITHelpers.h

    r207166 r207427  
    6060
    6161template<typename WrappedType, typename ToJSFunction>
    62 void toWrapper(CCallHelpers& jit, const JSC::DOMJIT::PatchpointParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
     62void toWrapper(CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
    6363{
    6464    ASSERT(wrapped != result.payloadGPR());
  • trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp

    r207239 r207427  
    5555    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
    5656    patchpoint->numGPScratchRegisters = 1;
    57     patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     57    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
    5858        JSValueRegs result = params[0].jsValueRegs();
    5959        GPRReg globalObject = params[1].gpr();
     
    8585{
    8686    Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
    87     patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     87    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
    8888        CCallHelpers::JumpList failureCases;
    8989        failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
     
    158158    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
    159159    patchpoint->requireGlobalObject = false;
    160     patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
     160    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
    161161        JSValueRegs result = params[0].jsValueRegs();
    162162        GPRReg node = params[1].gpr();
Note: See TracChangeset for help on using the changeset viewer.