Changeset 165141 in webkit


Ignore:
Timestamp:
Mar 5, 2014, 4:29:17 PM (11 years ago)
Author:
[email protected]
Message:

Support caching of custom setters
https://bugs.webkit.org/show_bug.cgi?id=129519

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch adds caching of assignment to properties that
are backed by C functions. This provides most of the leg
work required to start supporting setters, and resolves
the remaining regressions from moving DOM properties up
the prototype chain.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/PolymorphicPutByIdList.cpp:

(JSC::PutByIdAccess::visitWeak):
(JSC::PolymorphicPutByIdList::PolymorphicPutByIdList):
(JSC::PolymorphicPutByIdList::from):

  • bytecode/PolymorphicPutByIdList.h:

(JSC::PutByIdAccess::transition):
(JSC::PutByIdAccess::replace):
(JSC::PutByIdAccess::customSetter):
(JSC::PutByIdAccess::isCustom):
(JSC::PutByIdAccess::oldStructure):
(JSC::PutByIdAccess::chain):
(JSC::PutByIdAccess::stubRoutine):

  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::computeFor):
(JSC::PutByIdStatus::dump):

  • bytecode/PutByIdStatus.h:

(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::takesSlowPath):
(JSC::PutByIdStatus::makesCalls):

  • bytecode/StructureStubInfo.h:
  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::emitPutById):
(JSC::DFG::ByteCodeParser::handlePutById):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGCommon.h:
  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasIdentifier):

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

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileIn):

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

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • jit/CCallHelpers.h:

(JSC::CCallHelpers::setupArgumentsWithExecState):

  • jit/JITInlineCacheGenerator.cpp:

(JSC::JITByIdGenerator::JITByIdGenerator):
(JSC::JITPutByIdGenerator::JITPutByIdGenerator):

  • jit/JITInlineCacheGenerator.h:

(JSC::JITGetByIdGenerator::JITGetByIdGenerator):

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

(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_by_id):
(JSC::JIT::emit_op_put_by_id):

  • jit/Repatch.cpp:

(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):
(JSC::emitCustomSetterStub):
(JSC::tryCachePutByID):
(JSC::tryBuildPutByIdList):

  • jit/SpillRegistersMode.h: Added.
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/Lookup.h:

(JSC::putEntry):

  • runtime/PutPropertySlot.h:

(JSC::PutPropertySlot::setCacheableCustomProperty):
(JSC::PutPropertySlot::customSetter):
(JSC::PutPropertySlot::isCacheablePut):
(JSC::PutPropertySlot::isCacheableCustomProperty):
(JSC::PutPropertySlot::cachedOffset):

Source/WebCore:

Add forwarding header

Tests: js/regress/assign-custom-setter-polymorphic.html

js/regress/assign-custom-setter.html

  • ForwardingHeaders/jit/SpillRegistersMode.h: Added.

LayoutTests:

Add test cases.

  • js/regress/assign-custom-setter-expected.txt: Added.
  • js/regress/assign-custom-setter-polymorphic-expected.txt: Added.
  • js/regress/assign-custom-setter-polymorphic.html: Added.
  • js/regress/assign-custom-setter.html: Added.
  • js/regress/script-tests/assign-custom-setter-polymorphic.js: Added.

(test):

  • js/regress/script-tests/assign-custom-setter.js: Added.

(test):

Location:
trunk
Files:
8 added
34 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r165138 r165141  
     12014-03-05  Oliver Hunt  <[email protected]>
     2
     3        Support caching of custom setters
     4        https://bugs.webkit.org/show_bug.cgi?id=129519
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Add test cases.
     9
     10        * js/regress/assign-custom-setter-expected.txt: Added.
     11        * js/regress/assign-custom-setter-polymorphic-expected.txt: Added.
     12        * js/regress/assign-custom-setter-polymorphic.html: Added.
     13        * js/regress/assign-custom-setter.html: Added.
     14        * js/regress/script-tests/assign-custom-setter-polymorphic.js: Added.
     15        (test):
     16        * js/regress/script-tests/assign-custom-setter.js: Added.
     17        (test):
     18
    1192014-03-05  David Kilzer  <[email protected]>
    220
  • trunk/Source/JavaScriptCore/ChangeLog

    r165135 r165141  
     12014-03-03  Oliver Hunt  <[email protected]>
     2
     3        Support caching of custom setters
     4        https://bugs.webkit.org/show_bug.cgi?id=129519
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch adds caching of assignment to properties that
     9        are backed by C functions. This provides most of the leg
     10        work required to start supporting setters, and resolves
     11        the remaining regressions from moving DOM properties up
     12        the prototype chain.
     13
     14        * JavaScriptCore.xcodeproj/project.pbxproj:
     15        * bytecode/PolymorphicPutByIdList.cpp:
     16        (JSC::PutByIdAccess::visitWeak):
     17        (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList):
     18        (JSC::PolymorphicPutByIdList::from):
     19        * bytecode/PolymorphicPutByIdList.h:
     20        (JSC::PutByIdAccess::transition):
     21        (JSC::PutByIdAccess::replace):
     22        (JSC::PutByIdAccess::customSetter):
     23        (JSC::PutByIdAccess::isCustom):
     24        (JSC::PutByIdAccess::oldStructure):
     25        (JSC::PutByIdAccess::chain):
     26        (JSC::PutByIdAccess::stubRoutine):
     27        * bytecode/PutByIdStatus.cpp:
     28        (JSC::PutByIdStatus::computeForStubInfo):
     29        (JSC::PutByIdStatus::computeFor):
     30        (JSC::PutByIdStatus::dump):
     31        * bytecode/PutByIdStatus.h:
     32        (JSC::PutByIdStatus::PutByIdStatus):
     33        (JSC::PutByIdStatus::takesSlowPath):
     34        (JSC::PutByIdStatus::makesCalls):
     35        * bytecode/StructureStubInfo.h:
     36        * dfg/DFGAbstractInterpreterInlines.h:
     37        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     38        * dfg/DFGByteCodeParser.cpp:
     39        (JSC::DFG::ByteCodeParser::emitPutById):
     40        (JSC::DFG::ByteCodeParser::handlePutById):
     41        * dfg/DFGClobberize.h:
     42        (JSC::DFG::clobberize):
     43        * dfg/DFGCommon.h:
     44        * dfg/DFGConstantFoldingPhase.cpp:
     45        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     46        * dfg/DFGFixupPhase.cpp:
     47        (JSC::DFG::FixupPhase::fixupNode):
     48        * dfg/DFGNode.h:
     49        (JSC::DFG::Node::hasIdentifier):
     50        * dfg/DFGNodeType.h:
     51        * dfg/DFGPredictionPropagationPhase.cpp:
     52        (JSC::DFG::PredictionPropagationPhase::propagate):
     53        * dfg/DFGSafeToExecute.h:
     54        (JSC::DFG::safeToExecute):
     55        * dfg/DFGSpeculativeJIT.cpp:
     56        (JSC::DFG::SpeculativeJIT::compileIn):
     57        * dfg/DFGSpeculativeJIT.h:
     58        * dfg/DFGSpeculativeJIT32_64.cpp:
     59        (JSC::DFG::SpeculativeJIT::cachedGetById):
     60        (JSC::DFG::SpeculativeJIT::cachedPutById):
     61        (JSC::DFG::SpeculativeJIT::compile):
     62        * dfg/DFGSpeculativeJIT64.cpp:
     63        (JSC::DFG::SpeculativeJIT::cachedGetById):
     64        (JSC::DFG::SpeculativeJIT::cachedPutById):
     65        (JSC::DFG::SpeculativeJIT::compile):
     66        * jit/CCallHelpers.h:
     67        (JSC::CCallHelpers::setupArgumentsWithExecState):
     68        * jit/JITInlineCacheGenerator.cpp:
     69        (JSC::JITByIdGenerator::JITByIdGenerator):
     70        (JSC::JITPutByIdGenerator::JITPutByIdGenerator):
     71        * jit/JITInlineCacheGenerator.h:
     72        (JSC::JITGetByIdGenerator::JITGetByIdGenerator):
     73        * jit/JITOperations.cpp:
     74        * jit/JITOperations.h:
     75        * jit/JITPropertyAccess.cpp:
     76        (JSC::JIT::emit_op_get_by_id):
     77        (JSC::JIT::emit_op_put_by_id):
     78        * jit/JITPropertyAccess32_64.cpp:
     79        (JSC::JIT::emit_op_get_by_id):
     80        (JSC::JIT::emit_op_put_by_id):
     81        * jit/Repatch.cpp:
     82        (JSC::tryCacheGetByID):
     83        (JSC::tryBuildGetByIDList):
     84        (JSC::emitCustomSetterStub):
     85        (JSC::tryCachePutByID):
     86        (JSC::tryBuildPutByIdList):
     87        * jit/SpillRegistersMode.h: Added.
     88        * llint/LLIntSlowPaths.cpp:
     89        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     90        * runtime/Lookup.h:
     91        (JSC::putEntry):
     92        * runtime/PutPropertySlot.h:
     93        (JSC::PutPropertySlot::setCacheableCustomProperty):
     94        (JSC::PutPropertySlot::customSetter):
     95        (JSC::PutPropertySlot::isCacheablePut):
     96        (JSC::PutPropertySlot::isCacheableCustomProperty):
     97        (JSC::PutPropertySlot::cachedOffset):
     98
    1992014-03-05  Mark Hahnenberg  <[email protected]>
    2100
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r165074 r165141  
    11631163                A78507D617CBC6FD0011F6E7 /* MapData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78507D417CBC6FD0011F6E7 /* MapData.cpp */; };
    11641164                A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A78507D517CBC6FD0011F6E7 /* MapData.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1165                A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
    11651166                A78853F917972629001440E4 /* IntendedStructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78853F717972629001440E4 /* IntendedStructureChain.cpp */; };
    11661167                A78853FA17972629001440E4 /* IntendedStructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = A78853F817972629001440E4 /* IntendedStructureChain.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    28022803                A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyDescriptor.cpp; sourceTree = "<group>"; };
    28032804                A7FCC26C17A0B6AA00786D1A /* FTLSwitchCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSwitchCase.h; path = ftl/FTLSwitchCase.h; sourceTree = "<group>"; };
     2805                A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpillRegistersMode.h; sourceTree = "<group>"; };
    28042806                A8A4748D151A8306004123FF /* libWTF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libWTF.a; sourceTree = BUILT_PRODUCTS_DIR; };
    28052807                A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
     
    34703472                                A7386553118697B400540279 /* ThunkGenerators.h */,
    34713473                                65987F2F16828A7E003C2F8D /* UnusedPointer.h */,
     3474                                A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */,
    34723475                        );
    34733476                        path = jit;
     
    55245527                                BC18C4540E16F5CD00B34460 /* PropertyNameArray.h in Headers */,
    55255528                                0FF7168C15A3B235008F5DAA /* PropertyOffset.h in Headers */,
     5529                                A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */,
    55265530                                BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */,
    55275531                                0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */,
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp

    r164971 r165141  
    7878            return false;
    7979        break;
     80    case CustomSetter:
     81        if (!Heap::isMarked(m_oldStructure.get()))
     82            return false;
     83        if (m_chain && !Heap::isMarked(m_chain.get()))
     84            return false;
     85        break;
    8086    default:
    8187        RELEASE_ASSERT_NOT_REACHED();
     
    8995    : m_kind(putKind)
    9096{
    91     m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo));
     97    if (stubInfo.accessType != access_unset)
     98        m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo));
    9299}
    93100
     
    99106   
    100107    ASSERT(stubInfo.accessType == access_put_by_id_replace
    101            || stubInfo.accessType == access_put_by_id_transition_normal
    102            || stubInfo.accessType == access_put_by_id_transition_direct);
     108        || stubInfo.accessType == access_put_by_id_transition_normal
     109        || stubInfo.accessType == access_put_by_id_transition_direct
     110        || stubInfo.accessType == access_unset);
    103111   
    104112    PolymorphicPutByIdList* result =
  • trunk/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h

    r164971 r165141  
    3333#include "Opcode.h"
    3434#include "PutKind.h"
     35#include "PutPropertySlot.h"
    3536#include "Structure.h"
    3637#include <wtf/Vector.h>
     
    4647        Invalid,
    4748        Transition,
    48         Replace
     49        Replace,
     50        CustomSetter
    4951    };
    5052   
     
    6769        result.m_newStructure.set(vm, owner, newStructure);
    6870        result.m_chain.set(vm, owner, chain);
     71        result.m_customSetter = 0;
    6972        result.m_stubRoutine = stubRoutine;
    7073        return result;
    7174    }
    72    
     75
    7376    static PutByIdAccess replace(
    7477        VM& vm,
     
    8083        result.m_type = Replace;
    8184        result.m_oldStructure.set(vm, owner, structure);
     85        result.m_customSetter = 0;
    8286        result.m_stubRoutine = stubRoutine;
    8387        return result;
    8488    }
     89
     90
     91    static PutByIdAccess customSetter(
     92        VM& vm,
     93        JSCell* owner,
     94        Structure* structure,
     95        StructureChain* chain,
     96        PutPropertySlot::PutValueFunc customSetter,
     97        PassRefPtr<JITStubRoutine> stubRoutine)
     98    {
     99        PutByIdAccess result;
     100        result.m_oldStructure.set(vm, owner, structure);
     101        result.m_type = CustomSetter;
     102        if (chain)
     103            result.m_chain.set(vm, owner, chain);
     104        result.m_customSetter = customSetter;
     105        result.m_stubRoutine = stubRoutine;
     106        return result;
     107    }
    85108   
    86109    static PutByIdAccess fromStructureStubInfo(StructureStubInfo&);
     
    93116    bool isTransition() const { return m_type == Transition; }
    94117    bool isReplace() const { return m_type == Replace; }
     118    bool isCustom() const { return m_type == CustomSetter; }
    95119   
    96120    Structure* oldStructure() const
     
    98122        // Using this instead of isSet() to make this assertion robust against the possibility
    99123        // of additional access types being added.
    100         ASSERT(isTransition() || isReplace());
     124        ASSERT(isTransition() || isReplace() || isCustom());
    101125       
    102126        return m_oldStructure.get();
     
    117141    StructureChain* chain() const
    118142    {
    119         ASSERT(isTransition());
     143        ASSERT(isTransition() || isCustom());
    120144        return m_chain.get();
    121145    }
     
    123147    JITStubRoutine* stubRoutine() const
    124148    {
    125         ASSERT(isTransition() || isReplace());
     149        ASSERT(isTransition() || isReplace() || isCustom());
    126150        return m_stubRoutine.get();
    127151    }
    128    
     152
     153    PutPropertySlot::PutValueFunc customSetter() const { ASSERT(isCustom()); return m_customSetter; }
     154
    129155    bool visitWeak() const;
    130156   
     
    136162    WriteBarrier<Structure> m_newStructure;
    137163    WriteBarrier<StructureChain> m_chain;
     164    PutPropertySlot::PutValueFunc m_customSetter;
    138165    RefPtr<JITStubRoutine> m_stubRoutine;
    139166};
  • trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp

    r165129 r165141  
    206206                break;
    207207            }
     208            case PutByIdAccess::CustomSetter:
     209                return PutByIdStatus(MakesCalls);
    208210
    209211            default:
     
    266268    PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
    267269    if (isValidOffset(offset)) {
     270        if (attributes & CustomAccessor)
     271            return PutByIdStatus(MakesCalls);
     272
    268273        if (attributes & (Accessor | ReadOnly))
    269274            return PutByIdStatus(TakesSlowPath);
     
    343348        out.print("(TakesSlowPath)");
    344349        return;
     350    case MakesCalls:
     351        out.print("(MakesCalls)");
     352        return;
    345353    }
    346354   
  • trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h

    r165129 r165141  
    4848        Simple,
    4949        // It's known to often take slow path.
    50         TakesSlowPath
     50        TakesSlowPath,
     51        // It's known to take paths that make calls.
     52        MakesCalls
    5153    };
    5254   
     
    5961        : m_state(state)
    6062    {
    61         ASSERT(m_state == NoInformation || m_state == TakesSlowPath);
     63        ASSERT(m_state == NoInformation || m_state == TakesSlowPath || m_state == MakesCalls);
    6264    }
    6365   
     
    7880    bool operator!() const { return m_state == NoInformation; }
    7981    bool isSimple() const { return m_state == Simple; }
    80     bool takesSlowPath() const { return m_state == TakesSlowPath; }
     82    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
     83    bool makesCalls() const { return m_state == MakesCalls; }
    8184   
    8285    size_t numVariants() const { return m_variants.size(); }
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h

    r164747 r165141  
    3434#include "PolymorphicAccessStructureList.h"
    3535#include "RegisterSet.h"
     36#include "SpillRegistersMode.h"
    3637#include "Structure.h"
    3738#include "StructureStubClearingWatchpoint.h"
     
    194195
    195196    struct {
    196         int8_t registersFlushed;
     197        SpillRegistersMode spillMode : 8;
    197198        int8_t baseGPR;
    198199#if USE(JSVALUE32_64)
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r165099 r165141  
    17381738       
    17391739    case PutById:
     1740    case PutByIdFlush:
    17401741    case PutByIdDirect:
    17411742        node->setCanExit(true);
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r164620 r165141  
    181181        const GetByIdStatus&);
    182182    void emitPutById(
    183         Node* base, unsigned identifierNumber, Node* value, bool isDirect);
     183        Node* base, unsigned identifierNumber, Node* value,  const PutByIdStatus&, bool isDirect);
    184184    void handlePutById(
    185185        Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&,
     
    19441944
    19451945void ByteCodeParser::emitPutById(
    1946     Node* base, unsigned identifierNumber, Node* value, bool isDirect)
     1946    Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus& putByIdStatus, bool isDirect)
    19471947{
    19481948    if (isDirect)
    19491949        addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value);
    19501950    else
    1951         addToGraph(PutById, OpInfo(identifierNumber), base, value);
     1951        addToGraph(putByIdStatus.makesCalls() ? PutByIdFlush : PutById, OpInfo(identifierNumber), base, value);
    19521952}
    19531953
     
    19591959        if (!putByIdStatus.isSet())
    19601960            addToGraph(ForceOSRExit);
    1961         emitPutById(base, identifierNumber, value, isDirect);
     1961        emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
    19621962        return;
    19631963    }
     
    19651965    if (putByIdStatus.numVariants() > 1) {
    19661966        if (!isFTL(m_graph.m_plan.mode)) {
    1967             emitPutById(base, identifierNumber, value, isDirect);
     1967            emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
    19681968            return;
    19691969        }
     
    20022002    }
    20032003   
    2004     ASSERT(variant.kind() == PutByIdVariant::Transition);
     2004    if (variant.kind() != PutByIdVariant::Transition) {
     2005        emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
     2006        return;
     2007    }
     2008
    20052009    if (variant.structureChain() && !variant.structureChain()->isStillValid()) {
    2006         emitPutById(base, identifierNumber, value, isDirect);
     2010        emitPutById(base, identifierNumber, value, putByIdStatus, isDirect);
    20072011        return;
    20082012    }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r164764 r165141  
    197197    case GetByIdFlush:
    198198    case PutById:
     199    case PutByIdFlush:
    199200    case PutByIdDirect:
    200201    case ArrayPush:
  • trunk/Source/JavaScriptCore/dfg/DFGCommon.h

    r164424 r165141  
    9696#endif
    9797}
    98 
    99 enum SpillRegistersMode { NeedToSpill, DontSpill };
    10098
    10199enum NoResultTag { NoResult };
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r164620 r165141  
    225225               
    226226            case PutById:
     227            case PutByIdFlush:
    227228            case PutByIdDirect: {
    228229                NodeOrigin origin = node->origin;
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r165099 r165141  
    852852           
    853853        case PutById:
     854        case PutByIdFlush:
    854855        case PutByIdDirect: {
    855856            fixEdge<CellUse>(node->child1());
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r165099 r165141  
    655655        case GetByIdFlush:
    656656        case PutById:
     657        case PutByIdFlush:
    657658        case PutByIdDirect:
    658659            return true;
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r164620 r165141  
    147147    macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
    148148    macro(PutById, NodeMustGenerate | NodeClobbersWorld) \
     149    macro(PutByIdFlush, NodeMustGenerate | NodeMustGenerate | NodeClobbersWorld) \
    149150    macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \
    150151    macro(CheckStructure, NodeMustGenerate) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r164620 r165141  
    551551        case Throw:
    552552        case PutById:
     553        case PutByIdFlush:
    553554        case PutByIdDirect:
    554555        case PutByOffset:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r165099 r165141  
    156156    case GetByIdFlush:
    157157    case PutById:
     158    case PutByIdFlush:
    158159    case PutByIdDirect:
    159160    case CheckStructure:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r165135 r165141  
    881881            stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR);
    882882            stubInfo->patch.usedRegisters = usedRegisters();
    883             stubInfo->patch.registersFlushed = false;
     883            stubInfo->patch.spillMode = NeedToSpill;
    884884           
    885885            m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo));
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r165135 r165141  
    718718#if USE(JSVALUE64)
    719719    void cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
    720     void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
     720    void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
    721721#elif USE(JSVALUE32_64)
    722722    void cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
    723     void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
     723    void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
    724724#endif
    725725   
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r165135 r165141  
    175175        m_jit.codeBlock(), codeOrigin, usedRegisters(),
    176176        JSValueRegs(baseTagGPROrNone, basePayloadGPR),
    177         JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode != NeedToSpill);
     177        JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode);
    178178   
    179179    gen.generateFastPath(m_jit);
     
    202202}
    203203
    204 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
     204void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
    205205{
    206206    JITPutByIdGenerator gen(
    207207        m_jit.codeBlock(), codeOrigin, usedRegisters(),
    208208        JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR),
    209         scratchGPR, false, m_jit.ecmaModeFor(codeOrigin), putKind);
     209        scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
    210210   
    211211    gen.generateFastPath(m_jit);
     
    39193919        break;
    39203920    }
     3921
     3922    case PutByIdFlush: {
     3923        SpeculateCellOperand base(this, node->child1());
     3924        JSValueOperand value(this, node->child2());
     3925        GPRTemporary scratch(this);
     3926
     3927        GPRReg baseGPR = base.gpr();
     3928        GPRReg valueTagGPR = value.tagGPR();
     3929        GPRReg valuePayloadGPR = value.payloadGPR();
     3930        GPRReg scratchGPR = scratch.gpr();
     3931        flushRegisters();
     3932
     3933        cachedPutById(node->origin.semantic, baseGPR, valueTagGPR, valuePayloadGPR, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
     3934
     3935        noResult(node);
     3936        break;
     3937    }
    39213938       
    39223939    case PutById: {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r165135 r165141  
    3838#include "JSCInlines.h"
    3939#include "ObjectPrototype.h"
     40#include "SpillRegistersMode.h"
    4041
    4142namespace JSC { namespace DFG {
     
    192193    JITGetByIdGenerator gen(
    193194        m_jit.codeBlock(), codeOrigin, usedRegisters(), JSValueRegs(baseGPR),
    194         JSValueRegs(resultGPR), spillMode != NeedToSpill);
     195        JSValueRegs(resultGPR), spillMode);
    195196    gen.generateFastPath(m_jit);
    196197   
     
    208209}
    209210
    210 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
     211void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode)
    211212{
    212213    JITPutByIdGenerator gen(
    213214        m_jit.codeBlock(), codeOrigin, usedRegisters(), JSValueRegs(baseGPR),
    214         JSValueRegs(valueGPR), scratchGPR, false, m_jit.ecmaModeFor(codeOrigin), putKind);
     215        JSValueRegs(valueGPR), scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind);
     216
    215217    gen.generateFastPath(m_jit);
    216218   
     
    42494251        break;
    42504252    }
     4253
     4254    case PutByIdFlush: {
     4255        SpeculateCellOperand base(this, node->child1());
     4256        JSValueOperand value(this, node->child2());
     4257        GPRTemporary scratch(this);
     4258
     4259        GPRReg baseGPR = base.gpr();
     4260        GPRReg valueGPR = value.gpr();
     4261        GPRReg scratchGPR = scratch.gpr();
     4262        flushRegisters();
     4263
     4264        cachedPutById(node->origin.semantic, baseGPR, valueGPR, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill);
     4265
     4266        noResult(node);
     4267        break;
     4268    }
    42514269       
    42524270    case PutById: {
  • trunk/Source/JavaScriptCore/jit/CCallHelpers.h

    r164631 r165141  
    372372        addCallArgument(arg3);
    373373        addCallArgument(arg4);
     374    }
     375   
     376    ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
     377    {
     378        resetCallArguments();
     379        addCallArgument(GPRInfo::callFrameRegister);
     380        addCallArgument(arg1);
     381        addCallArgument(arg2);
     382        addCallArgument(arg3);
     383        addCallArgument(arg4);
     384        addCallArgument(arg5);
    374385    }
    375386
  • trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp

    r164764 r165141  
    5050JITByIdGenerator::JITByIdGenerator(
    5151    CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters,
    52     JSValueRegs base, JSValueRegs value, bool registersFlushed)
     52    JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode)
    5353    : JITInlineCacheGenerator(codeBlock, codeOrigin)
    5454    , m_base(base)
    5555    , m_value(value)
    5656{
    57     m_stubInfo->patch.registersFlushed = registersFlushed;
     57    m_stubInfo->patch.spillMode = spillMode;
    5858    m_stubInfo->patch.usedRegisters = usedRegisters;
    5959   
     
    130130JITPutByIdGenerator::JITPutByIdGenerator(
    131131    CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters,
    132     JSValueRegs base, JSValueRegs value, GPRReg scratch, bool registersFlushed,
     132    JSValueRegs base, JSValueRegs value, GPRReg scratch, SpillRegistersMode spillMode,
    133133    ECMAMode ecmaMode, PutKind putKind)
    134     : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, registersFlushed)
     134    : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, spillMode)
    135135    , m_scratch(scratch)
    136136    , m_ecmaMode(ecmaMode)
  • trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h

    r164764 r165141  
    5858    JITByIdGenerator(
    5959        CodeBlock*, CodeOrigin, const RegisterSet&, JSValueRegs base, JSValueRegs value,
    60         bool registersFlushed);
     60        SpillRegistersMode spillMode);
    6161   
    6262public:
     
    9696
    9797    JITGetByIdGenerator(
    98         CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters,
    99         JSValueRegs base, JSValueRegs value, bool registersFlushed)
    100         : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, registersFlushed)
     98    CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters,
     99    JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode)
     100    : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, spillMode)
    101101    {
    102102    }
     
    111111    JITPutByIdGenerator(
    112112        CodeBlock*, CodeOrigin, const RegisterSet& usedRegisters, JSValueRegs base,
    113         JSValueRegs value, GPRReg scratch, bool registersFlushed, ECMAMode, PutKind);
     113        JSValueRegs, GPRReg scratch, SpillRegistersMode spillMode, ECMAMode, PutKind);
    114114   
    115115    void generateFastPath(MacroAssembler&);
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r165005 r165141  
    17311731    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
    17321732    if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
    1733         if (slot.isCacheable() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {
     1733        if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {
    17341734            ConcurrentJITLocker locker(codeBlock->m_lock);
    17351735            pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure());
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r164630 r165141  
    3636#include "MacroAssembler.h"
    3737#include "PutKind.h"
     38#include "SpillRegistersMode.h"
    3839#include "StructureStubInfo.h"
    3940#include "VariableWatchpointSet.h"
     41
    4042
    4143namespace JSC {
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r165135 r165141  
    522522    JITGetByIdGenerator gen(
    523523        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
    524         JSValueRegs(regT0), JSValueRegs(regT0), true);
     524        JSValueRegs(regT0), JSValueRegs(regT0), DontSpill);
    525525    gen.generateFastPath(*this);
    526526    addSlowCase(gen.slowPathJump());
     
    568568    JITPutByIdGenerator gen(
    569569        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
    570         JSValueRegs(regT0), JSValueRegs(regT1), regT2, true, m_codeBlock->ecmaMode(),
     570        JSValueRegs(regT0), JSValueRegs(regT1), regT2, DontSpill, m_codeBlock->ecmaMode(),
    571571        direct ? Direct : NotDirect);
    572572   
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r164764 r165141  
    479479    JITGetByIdGenerator gen(
    480480        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
    481         JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), true);
     481        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill);
    482482    gen.generateFastPath(*this);
    483483    addSlowCase(gen.slowPathJump());
     
    528528        m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(),
    529529        JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2),
    530         regT1, true, m_codeBlock->ecmaMode(), direct ? Direct : NotDirect);
     530        regT1, DontSpill, m_codeBlock->ecmaMode(), direct ? Direct : NotDirect);
    531531   
    532532    gen.generateFastPath(*this);
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r165135 r165141  
    450450        return false;
    451451
    452     if (!stubInfo.patch.registersFlushed) {
     452    if (stubInfo.patch.spillMode == NeedToSpill) {
    453453        // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular,
    454454        // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus,
     
    552552   
    553553    if (slot.slotBase() == baseValue) {
    554         if (!stubInfo.patch.registersFlushed) {
     554        if (stubInfo.patch.spillMode == NeedToSpill) {
    555555            // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular,
    556556            // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus,
     
    703703        return false;
    704704   
    705     if (!stubInfo.patch.registersFlushed) {
     705    if (stubInfo.patch.spillMode == NeedToSpill) {
    706706        // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular,
    707707        // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus,
     
    11301130}
    11311131
     1132static void emitCustomSetterStub(ExecState* exec, const PutPropertySlot& slot,
     1133    StructureStubInfo& stubInfo, Structure* structure, StructureChain* prototypeChain,
     1134    CodeLocationLabel failureLabel, RefPtr<JITStubRoutine>& stubRoutine)
     1135{
     1136    VM* vm = &exec->vm();
     1137    ASSERT(stubInfo.patch.spillMode == DontSpill);
     1138    GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR);
     1139#if USE(JSVALUE32_64)
     1140    GPRReg valueTagGPR = static_cast<GPRReg>(stubInfo.patch.valueTagGPR);
     1141#endif
     1142    GPRReg valueGPR = static_cast<GPRReg>(stubInfo.patch.valueGPR);
     1143    TempRegisterSet tempRegisters(stubInfo.patch.usedRegisters);
     1144
     1145    CCallHelpers stubJit(vm);
     1146    GPRReg scratchGPR = tempRegisters.getFreeGPR();
     1147    RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
     1148    RELEASE_ASSERT(scratchGPR != baseGPR);
     1149    RELEASE_ASSERT(scratchGPR != valueGPR);
     1150    MacroAssembler::JumpList failureCases;
     1151    failureCases.append(branchStructure(stubJit,
     1152        MacroAssembler::NotEqual,
     1153        MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()),
     1154        structure));
     1155   
     1156    if (prototypeChain) {
     1157        for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it)
     1158            addStructureTransitionCheck((*it)->storedPrototype(), exec->codeBlock(), stubInfo, stubJit, failureCases, scratchGPR);
     1159    }
     1160
     1161    // typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
     1162#if USE(JSVALUE64)
     1163    stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, valueGPR);
     1164#else
     1165    stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), valueGPR, valueTagGPR);
     1166#endif
     1167
     1168    // Need to make sure that whenever this call is made in the future, we remember the
     1169    // place that we made it from. It just so happens to be the place that we are at
     1170    // right now!
     1171    stubJit.store32(MacroAssembler::TrustedImm32(exec->locationAsRawBits()),
     1172        CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
     1173    stubJit.storePtr(GPRInfo::callFrameRegister, &vm->topCallFrame);
     1174
     1175    MacroAssembler::Call setterCall = stubJit.call();
     1176   
     1177    MacroAssembler::Jump success = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
     1178
     1179    stubJit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister);
     1180
     1181    MacroAssembler::Call handlerCall = stubJit.call();
     1182
     1183    stubJit.jumpToExceptionHandler();
     1184    LinkBuffer patchBuffer(*vm, &stubJit, exec->codeBlock());
     1185
     1186    patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
     1187    patchBuffer.link(failureCases, failureLabel);
     1188    patchBuffer.link(setterCall, FunctionPtr(slot.customSetter()));
     1189    patchBuffer.link(handlerCall, lookupExceptionHandler);
     1190
     1191    stubRoutine = createJITStubRoutine(
     1192        FINALIZE_CODE_FOR(exec->codeBlock(), patchBuffer, ("PutById custom setter stub for %s, return point %p",
     1193        toCString(*exec->codeBlock()).data(), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone).executableAddress())), *vm, exec->codeBlock()->ownerExecutable(), structure);
     1194}
     1195
     1196
    11321197static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
    11331198{
     
    11411206    Structure* oldStructure = structure->previousID();
    11421207   
    1143     if (!slot.isCacheable())
     1208    if (!slot.isCacheablePut() && !slot.isCacheableCustomProperty())
    11441209        return false;
    11451210    if (!structure->propertyAccessesAreCacheable())
     
    11471212
    11481213    // Optimize self access.
    1149     if (slot.base() == baseValue) {
     1214    if (slot.base() == baseValue && slot.isCacheablePut()) {
    11501215        if (slot.type() == PutPropertySlot::NewProperty) {
    11511216            if (structure->isDictionary())
     
    11941259        return true;
    11951260    }
     1261    if (slot.isCacheableCustomProperty() && stubInfo.patch.spillMode == DontSpill) {
     1262        RefPtr<JITStubRoutine> stubRoutine;
     1263
     1264        StructureChain* prototypeChain = 0;
     1265        if (baseValue != slot.base()) {
     1266            PropertyOffset offsetIgnored;
     1267            if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offsetIgnored) == InvalidPrototypeChain)
     1268                return false;
     1269
     1270            prototypeChain = structure->prototypeChain(exec);
     1271        }
     1272        PolymorphicPutByIdList* list;
     1273        list = PolymorphicPutByIdList::from(putKind, stubInfo);
     1274
     1275        emitCustomSetterStub(exec, slot, stubInfo,
     1276            structure, prototypeChain,
     1277            stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase),
     1278            stubRoutine);
     1279
     1280        list->addAccess(PutByIdAccess::customSetter(*vm, codeBlock->ownerExecutable(), structure, prototypeChain, slot.customSetter(), stubRoutine));
     1281
     1282        RepatchBuffer repatchBuffer(codeBlock);
     1283        repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code()));
     1284        repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind));
     1285        RELEASE_ASSERT(!list->isFull());
     1286        return true;
     1287    }
    11961288
    11971289    return false;
     
    12181310    Structure* oldStructure = structure->previousID();
    12191311   
    1220     if (!slot.isCacheable())
    1221         return false;
     1312   
     1313    if (!slot.isCacheablePut() && !slot.isCacheableCustomProperty())
     1314        return false;
     1315
    12221316    if (!structure->propertyAccessesAreCacheable())
    12231317        return false;
    12241318
    12251319    // Optimize self access.
    1226     if (slot.base() == baseValue) {
     1320    if (slot.base() == baseValue && slot.isCacheablePut()) {
    12271321        PolymorphicPutByIdList* list;
    12281322        RefPtr<JITStubRoutine> stubRoutine;
     
    12861380    }
    12871381
     1382    if (slot.isCacheableCustomProperty() && stubInfo.patch.spillMode == DontSpill) {
     1383        RefPtr<JITStubRoutine> stubRoutine;
     1384        StructureChain* prototypeChain = 0;
     1385        if (baseValue != slot.base()) {
     1386            PropertyOffset offsetIgnored;
     1387            if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offsetIgnored) == InvalidPrototypeChain)
     1388                return false;
     1389
     1390            prototypeChain = structure->prototypeChain(exec);
     1391        }
     1392        PolymorphicPutByIdList* list;
     1393        list = PolymorphicPutByIdList::from(putKind, stubInfo);
     1394
     1395        emitCustomSetterStub(exec, slot, stubInfo,
     1396            structure, prototypeChain,
     1397            CodeLocationLabel(list->currentSlowPathTarget()),
     1398            stubRoutine);
     1399
     1400        list->addAccess(PutByIdAccess::customSetter(*vm, codeBlock->ownerExecutable(), structure, prototypeChain, slot.customSetter(), stubRoutine));
     1401
     1402        RepatchBuffer repatchBuffer(codeBlock);
     1403        repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code()));
     1404        if (list->isFull())
     1405            repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
     1406
     1407        return true;
     1408    }
    12881409    return false;
    12891410}
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r164630 r165141  
    629629    if (!LLINT_ALWAYS_ACCESS_SLOW
    630630        && baseValue.isCell()
    631         && slot.isCacheable()) {
     631        && slot.isCacheablePut()) {
    632632       
    633633        JSCell* baseCell = baseValue.asCell();
     
    14111411    // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
    14121412    if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
    1413         if (slot.isCacheable() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {
     1413        if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {
    14141414            ConcurrentJITLocker locker(codeBlock->m_lock);
    14151415            pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure());
  • trunk/Source/JavaScriptCore/runtime/Lookup.h

    r163960 r165141  
    307307        } else if (!(entry->attributes() & ReadOnly)) {
    308308            entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value));
    309             slot.setCustomProperty(base, entry->propertyPutter());
     309            slot.setCacheableCustomProperty(base, entry->propertyPutter());
    310310        } else if (slot.isStrictMode())
    311311            throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  • trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h

    r162741 r165141  
    3939    class PutPropertySlot {
    4040    public:
    41         enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty };
     41        enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty, CacheableCustomProperty };
    4242        enum Context { UnknownContext, PutById, PutByIdEval };
    4343        typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
     
    7373            m_putFunction = function;
    7474        }
    75        
     75
     76        void setCacheableCustomProperty(JSObject* base, PutValueFunc function)
     77        {
     78            m_type = CacheableCustomProperty;
     79            m_base = base;
     80            m_putFunction = function;
     81        }
     82        PutValueFunc customSetter() const { return m_putFunction; }
     83
    7684        Context context() const { return static_cast<Context>(m_context); }
    7785
     
    8189
    8290        bool isStrictMode() const { return m_isStrictMode; }
    83         bool isCacheable() const { return m_type != Uncachable && m_type != CustomProperty; }
     91        bool isCacheablePut() const { return m_type == NewProperty || m_type == ExistingProperty; }
     92        bool isCacheableCustomProperty() const { return m_type == CacheableCustomProperty; }
     93
    8494        PropertyOffset cachedOffset() const
    8595        {
    86             ASSERT(isCacheable());
     96            ASSERT(isCacheablePut());
    8797            return m_offset;
    8898        }
  • trunk/Source/WebCore/ChangeLog

    r165138 r165141  
     12014-03-05  Oliver Hunt  <[email protected]>
     2
     3        Support caching of custom setters
     4        https://bugs.webkit.org/show_bug.cgi?id=129519
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Add forwarding header
     9
     10        Tests: js/regress/assign-custom-setter-polymorphic.html
     11               js/regress/assign-custom-setter.html
     12
     13        * ForwardingHeaders/jit/SpillRegistersMode.h: Added.
     14
    1152014-03-05  David Kilzer  <[email protected]>
    216
Note: See TracChangeset for help on using the changeset viewer.