Changeset 239324 in webkit


Ignore:
Timestamp:
Dec 17, 2018 10:54:49 PM (5 years ago)
Author:
yusukesuzuki@slowstart.org
Message:

[JSC] Optimize Object.keys by caching own keys results in StructureRareData
https://bugs.webkit.org/show_bug.cgi?id=190047

Reviewed by Saam Barati.

JSTests:

  • stress/object-keys-cached-zero.js: Added.

(shouldBe):
(test):

  • stress/object-keys-changed-attribute.js: Added.

(shouldBe):
(test):

  • stress/object-keys-changed-index.js: Added.

(shouldBe):
(test):

  • stress/object-keys-changed.js: Added.

(shouldBe):
(test):

  • stress/object-keys-indexed-non-cache.js: Added.

(shouldBe):
(test):

  • stress/object-keys-overrides-get-property-names.js: Added.

(shouldBe):
(test):
(noInline):

Source/JavaScriptCore:

Object.keys is one of the most frequently used function in web-tooling-benchmarks (WTB).
Object.keys is dominant in lebab of WTB, and frequently called in babel and others.
Since our Structure knows the shape of JSObject, we can cache the result of Object.keys
in Structure (StructureRareData) as we cache JSPropertyNameEnumerator in StructureRareData.

This patch caches the result of Object.keys in StructureRareData. The cached array is created
as JSImmutableButterfly. And Object.keys creates CoW from this data. Currently, the lifetime
strategy of this JSImmutableButterfly is the same to cached JSPropertyNameEnumerator. It is
referenced from Structure, and collected when Structure is collected.

This improves several benchmarks in SixSpeed.

baseline patched

object-assign.es5 350.1710+-3.6303 226.0368+-4.7558 definitely 1.5492x faster
for-of-object.es6 269.1941+-3.3430 127.9317+-2.3875 definitely 2.1042x faster

And it improves WTB lebab by 11.8%.

Before: lebab: 6.10 runs/s
After: lebab: 6.82 runs/s

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

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

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.cpp:

(JSC::DFG::Node::convertToNewArrayBuffer):

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileObjectKeys):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLAbstractHeapRepository.h:
  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

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

  • runtime/Butterfly.h:

(JSC::ContiguousData::Data::setStartingValue):

  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
  • runtime/JSImmutableButterfly.h:

(JSC::JSImmutableButterfly::JSImmutableButterfly):
We set JSEmpty to the underlying butterfly storage if indexing type is Contiguous.
Otherwise, JSImmutableButterfly is half-baked one until all the storage is filled with some meaningful values, it leads to crash
if half-baked JSImmutableButterfly is exposed to GC.

  • runtime/ObjectConstructor.cpp:

(JSC::ownPropertyKeys):

  • runtime/Structure.cpp:

(JSC::Structure::canCachePropertyNameEnumerator const):

  • runtime/Structure.h:
  • runtime/StructureInlines.h:

(JSC::Structure::setCachedOwnKeys):
(JSC::Structure::cachedOwnKeys const):
(JSC::Structure::cachedOwnKeysIgnoringSentinel const):
(JSC::Structure::canCacheOwnKeys const):

  • runtime/StructureRareData.cpp:

(JSC::StructureRareData::visitChildren):
(JSC::StructureRareData::cachedPropertyNameEnumerator const): Deleted.
(JSC::StructureRareData::setCachedPropertyNameEnumerator): Deleted.

  • runtime/StructureRareData.h:
  • runtime/StructureRareDataInlines.h:

(JSC::StructureRareData::cachedPropertyNameEnumerator const):
(JSC::StructureRareData::setCachedPropertyNameEnumerator):
(JSC::StructureRareData::cachedOwnKeys const):
(JSC::StructureRareData::cachedOwnKeysIgnoringSentinel const):
(JSC::StructureRareData::cachedOwnKeysConcurrently const):
(JSC::StructureRareData::setCachedOwnKeys):
(JSC::StructureRareData::previousID const): Deleted.

  • runtime/VM.cpp:

(JSC::VM::VM):

Location:
trunk
Files:
6 added
34 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r239304 r239324  
     12018-12-16  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     2
     3        [JSC] Optimize Object.keys by caching own keys results in StructureRareData
     4        https://bugs.webkit.org/show_bug.cgi?id=190047
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/object-keys-cached-zero.js: Added.
     9        (shouldBe):
     10        (test):
     11        * stress/object-keys-changed-attribute.js: Added.
     12        (shouldBe):
     13        (test):
     14        * stress/object-keys-changed-index.js: Added.
     15        (shouldBe):
     16        (test):
     17        * stress/object-keys-changed.js: Added.
     18        (shouldBe):
     19        (test):
     20        * stress/object-keys-indexed-non-cache.js: Added.
     21        (shouldBe):
     22        (test):
     23        * stress/object-keys-overrides-get-property-names.js: Added.
     24        (shouldBe):
     25        (test):
     26        (noInline):
     27
    1282018-12-17  Mark Lam  <mark.lam@apple.com>
    229
  • trunk/Source/JavaScriptCore/ChangeLog

    r239304 r239324  
     12018-12-16  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     2
     3        [JSC] Optimize Object.keys by caching own keys results in StructureRareData
     4        https://bugs.webkit.org/show_bug.cgi?id=190047
     5
     6        Reviewed by Saam Barati.
     7
     8        Object.keys is one of the most frequently used function in web-tooling-benchmarks (WTB).
     9        Object.keys is dominant in lebab of WTB, and frequently called in babel and others.
     10        Since our Structure knows the shape of JSObject, we can cache the result of Object.keys
     11        in Structure (StructureRareData) as we cache JSPropertyNameEnumerator in StructureRareData.
     12
     13        This patch caches the result of Object.keys in StructureRareData. The cached array is created
     14        as JSImmutableButterfly. And Object.keys creates CoW from this data. Currently, the lifetime
     15        strategy of this JSImmutableButterfly is the same to cached JSPropertyNameEnumerator. It is
     16        referenced from Structure, and collected when Structure is collected.
     17
     18        This improves several benchmarks in SixSpeed.
     19
     20                                        baseline                  patched
     21
     22            object-assign.es5      350.1710+-3.6303     ^    226.0368+-4.7558        ^ definitely 1.5492x faster
     23            for-of-object.es6      269.1941+-3.3430     ^    127.9317+-2.3875        ^ definitely 2.1042x faster
     24
     25        And it improves WTB lebab by 11.8%.
     26
     27            Before: lebab:  6.10 runs/s
     28            After:  lebab:  6.82 runs/s
     29
     30        * dfg/DFGAbstractInterpreterInlines.h:
     31        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     32        * dfg/DFGByteCodeParser.cpp:
     33        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     34        * dfg/DFGClobberize.h:
     35        (JSC::DFG::clobberize):
     36        * dfg/DFGConstantFoldingPhase.cpp:
     37        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     38        * dfg/DFGDoesGC.cpp:
     39        (JSC::DFG::doesGC):
     40        * dfg/DFGFixupPhase.cpp:
     41        (JSC::DFG::FixupPhase::fixupNode):
     42        * dfg/DFGNode.cpp:
     43        (JSC::DFG::Node::convertToNewArrayBuffer):
     44        * dfg/DFGNode.h:
     45        * dfg/DFGNodeType.h:
     46        * dfg/DFGOperations.cpp:
     47        * dfg/DFGOperations.h:
     48        * dfg/DFGPredictionPropagationPhase.cpp:
     49        * dfg/DFGSafeToExecute.h:
     50        (JSC::DFG::safeToExecute):
     51        * dfg/DFGSpeculativeJIT.cpp:
     52        (JSC::DFG::SpeculativeJIT::compileObjectKeys):
     53        * dfg/DFGSpeculativeJIT.h:
     54        * dfg/DFGSpeculativeJIT32_64.cpp:
     55        (JSC::DFG::SpeculativeJIT::compile):
     56        * dfg/DFGSpeculativeJIT64.cpp:
     57        (JSC::DFG::SpeculativeJIT::compile):
     58        * ftl/FTLAbstractHeapRepository.h:
     59        * ftl/FTLCapabilities.cpp:
     60        (JSC::FTL::canCompile):
     61        * ftl/FTLLowerDFGToB3.cpp:
     62        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     63        (JSC::FTL::DFG::LowerDFGToB3::compileObjectKeys):
     64        * runtime/Butterfly.h:
     65        (JSC::ContiguousData::Data::setStartingValue):
     66        * runtime/Intrinsic.cpp:
     67        (JSC::intrinsicName):
     68        * runtime/Intrinsic.h:
     69        * runtime/JSImmutableButterfly.h:
     70        (JSC::JSImmutableButterfly::JSImmutableButterfly):
     71        We set JSEmpty to the underlying butterfly storage if indexing type is Contiguous.
     72        Otherwise, JSImmutableButterfly is half-baked one until all the storage is filled with some meaningful values, it leads to crash
     73        if half-baked JSImmutableButterfly is exposed to GC.
     74        * runtime/ObjectConstructor.cpp:
     75        (JSC::ownPropertyKeys):
     76        * runtime/Structure.cpp:
     77        (JSC::Structure::canCachePropertyNameEnumerator const):
     78        * runtime/Structure.h:
     79        * runtime/StructureInlines.h:
     80        (JSC::Structure::setCachedOwnKeys):
     81        (JSC::Structure::cachedOwnKeys const):
     82        (JSC::Structure::cachedOwnKeysIgnoringSentinel const):
     83        (JSC::Structure::canCacheOwnKeys const):
     84        * runtime/StructureRareData.cpp:
     85        (JSC::StructureRareData::visitChildren):
     86        (JSC::StructureRareData::cachedPropertyNameEnumerator const): Deleted.
     87        (JSC::StructureRareData::setCachedPropertyNameEnumerator): Deleted.
     88        * runtime/StructureRareData.h:
     89        * runtime/StructureRareDataInlines.h:
     90        (JSC::StructureRareData::cachedPropertyNameEnumerator const):
     91        (JSC::StructureRareData::setCachedPropertyNameEnumerator):
     92        (JSC::StructureRareData::cachedOwnKeys const):
     93        (JSC::StructureRareData::cachedOwnKeysIgnoringSentinel const):
     94        (JSC::StructureRareData::cachedOwnKeysConcurrently const):
     95        (JSC::StructureRareData::setCachedOwnKeys):
     96        (JSC::StructureRareData::previousID const): Deleted.
     97        * runtime/VM.cpp:
     98        (JSC::VM::VM):
     99
    11002018-12-17  Mark Lam  <mark.lam@apple.com>
    2101
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r239231 r239324  
    4444#include "PutByIdStatus.h"
    4545#include "StringObject.h"
     46#include "StructureRareDataInlines.h"
    4647#include <wtf/BooleanLattice.h>
    4748#include <wtf/CheckedArithmetic.h>
     
    25782579            clobberWorld();
    25792580        setTypeForNode(node, SpecFinalObject);
     2581        break;
     2582    }
     2583
     2584    case ObjectKeys: {
     2585        if (node->child1().useKind() == ObjectUse) {
     2586            auto& structureSet = forNode(node->child1()).m_structure;
     2587            if (structureSet.isFinite() && structureSet.size() == 1) {
     2588                RegisteredStructure structure = structureSet.onlyStructure();
     2589                if (auto* rareData = structure->rareDataConcurrently()) {
     2590                    if (auto* immutableButterfly = rareData->cachedOwnKeysConcurrently()) {
     2591                        if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
     2592                            m_state.setFoundConstants(true);
     2593                            didFoldClobberWorld();
     2594                            setTypeForNode(node, SpecArray);
     2595                            break;
     2596                        }
     2597                    }
     2598                }
     2599            }
     2600        }
     2601
     2602        clobberWorld();
     2603        setTypeForNode(node, SpecArray);
    25802604        break;
    25812605    }
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r239231 r239324  
    26902690        insertChecks();
    26912691        set(result, addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))));
     2692        return true;
     2693    }
     2694
     2695    case ObjectKeysIntrinsic: {
     2696        if (argumentCountIncludingThis < 2)
     2697            return false;
     2698
     2699        insertChecks();
     2700        set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset))));
    26922701        return true;
    26932702    }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r239231 r239324  
    669669    case InstanceOf:
    670670    case StringValueOf:
     671    case ObjectKeys:
    671672        read(World);
    672673        write(Heap);
     
    15291530        }
    15301531    }
    1531 
    15321532
    15331533    case NewObject:
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r239231 r239324  
    767767            }
    768768
     769            case ObjectKeys: {
     770                if (node->child1().useKind() == ObjectUse) {
     771                    auto& structureSet = m_state.forNode(node->child1()).m_structure;
     772                    if (structureSet.isFinite() && structureSet.size() == 1) {
     773                        RegisteredStructure structure = structureSet.onlyStructure();
     774                        if (auto* rareData = structure->rareDataConcurrently()) {
     775                            if (auto* immutableButterfly = rareData->cachedOwnKeysConcurrently()) {
     776                                if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
     777                                    node->convertToNewArrayBuffer(m_graph.freeze(immutableButterfly));
     778                                    changed = true;
     779                                    break;
     780                                }
     781                            }
     782                        }
     783                    }
     784                }
     785                break;
     786            }
     787
    769788            case ToNumber: {
    770789                if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber)
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r239231 r239324  
    340340    case CreateThis:
    341341    case ObjectCreate:
     342    case ObjectKeys:
    342343    case AllocatePropertyStorage:
    343344    case ReallocatePropertyStorage:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r239287 r239324  
    15921592                node->clearFlags(NodeMustGenerate);
    15931593                break;
     1594            }
     1595            break;
     1596        }
     1597
     1598        case ObjectKeys: {
     1599            if (node->child1()->shouldSpeculateObject()) {
     1600                watchHavingABadTime(node);
     1601                fixEdge<ObjectUse>(node->child1());
    15941602            }
    15951603            break;
  • trunk/Source/JavaScriptCore/dfg/DFGNode.cpp

    r239231 r239324  
    3232#include "DFGPromotedHeapLocation.h"
    3333#include "JSCInlines.h"
     34#include "JSImmutableButterfly.h"
    3435
    3536namespace JSC { namespace DFG {
     
    224225}
    225226
     227void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly)
     228{
     229    setOpAndDefaultFlags(NewArrayBuffer);
     230    NewArrayBufferData data { };
     231    data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode();
     232    data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength();
     233    children.reset();
     234    m_opInfo = immutableButterfly;
     235    m_opInfo2 = data.asQuadWord;
     236}
     237
    226238void Node::convertToDirectCall(FrozenValue* executable)
    227239{
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r239231 r239324  
    762762        m_opInfo2 = OpInfoWrapper();
    763763    }
     764
     765    void convertToNewArrayBuffer(FrozenValue* immutableButterfly);
    764766   
    765767    void convertToDirectCall(FrozenValue*);
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r239231 r239324  
    266266    macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \
    267267    macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \
     268    macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \
    268269    \
    269270    /* Atomics object functions. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r239231 r239324  
    249249}
    250250
     251JSArray* JIT_OPERATION operationObjectKeys(ExecState* exec, EncodedJSValue encodedObject)
     252{
     253    VM& vm = exec->vm();
     254    NativeCallFrameTracer tracer(&vm, exec);
     255    auto scope = DECLARE_THROW_SCOPE(vm);
     256
     257    JSObject* object = JSValue::decode(encodedObject).toObject(exec);
     258    RETURN_IF_EXCEPTION(scope, nullptr);
     259    scope.release();
     260    return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
     261}
     262
     263JSArray* JIT_OPERATION operationObjectKeysObject(ExecState* exec, JSObject* object)
     264{
     265    VM& vm = exec->vm();
     266    NativeCallFrameTracer tracer(&vm, exec);
     267    return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
     268}
     269
    251270JSCell* JIT_OPERATION operationObjectCreate(ExecState* exec, EncodedJSValue encodedPrototype)
    252271{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r239231 r239324  
    4444JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget) WTF_INTERNAL;
    4545JSCell* JIT_OPERATION operationToObject(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget, UniquedStringImpl*) WTF_INTERNAL;
     46JSArray* JIT_OPERATION operationObjectKeys(ExecState*, EncodedJSValue) WTF_INTERNAL;
     47JSArray* JIT_OPERATION operationObjectKeysObject(ExecState*, JSObject*) WTF_INTERNAL;
    4648JSCell* JIT_OPERATION operationObjectCreate(ExecState*, EncodedJSValue) WTF_INTERNAL;
    4749JSCell* JIT_OPERATION operationObjectCreateObject(ExecState*, JSObject*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r239231 r239324  
    985985        case NewArrayWithSize:
    986986        case CreateRest:
    987         case NewArrayBuffer: {
     987        case NewArrayBuffer:
     988        case ObjectKeys: {
    988989            setPrediction(SpecArray);
    989990            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r239231 r239324  
    179179    case CreateThis:
    180180    case ObjectCreate:
     181    case ObjectKeys:
    181182    case GetCallee:
    182183    case SetCallee:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r239231 r239324  
    1236612366}
    1236712367
     12368void SpeculativeJIT::compileObjectKeys(Node* node)
     12369{
     12370    switch (node->child1().useKind()) {
     12371    case ObjectUse: {
     12372        if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
     12373            SpeculateCellOperand object(this, node->child1());
     12374            GPRTemporary structure(this);
     12375            GPRTemporary scratch(this);
     12376            GPRTemporary scratch2(this);
     12377            GPRTemporary scratch3(this);
     12378            GPRTemporary result(this);
     12379
     12380            GPRReg objectGPR = object.gpr();
     12381            GPRReg structureGPR = structure.gpr();
     12382            GPRReg scratchGPR = scratch.gpr();
     12383            GPRReg scratch2GPR = scratch2.gpr();
     12384            GPRReg scratch3GPR = scratch3.gpr();
     12385            GPRReg resultGPR = result.gpr();
     12386
     12387            speculateObject(node->child1(), objectGPR);
     12388
     12389            CCallHelpers::JumpList slowCases;
     12390            m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR);
     12391            m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
     12392
     12393            slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
     12394            slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID()))));
     12395
     12396            m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR);
     12397
     12398            ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1);
     12399            slowCases.append(m_jit.branchPtr(CCallHelpers::BelowOrEqual, scratchGPR, TrustedImmPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))));
     12400
     12401            MacroAssembler::JumpList slowButArrayBufferCases;
     12402
     12403            JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
     12404            RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
     12405
     12406            m_jit.move(scratchGPR, scratch3GPR);
     12407            m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
     12408
     12409            emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
     12410
     12411            addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR));
     12412
     12413            addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR));
     12414
     12415            cellResult(resultGPR, node);
     12416            break;
     12417        }
     12418
     12419        SpeculateCellOperand object(this, node->child1());
     12420
     12421        GPRReg objectGPR = object.gpr();
     12422
     12423        speculateObject(node->child1(), objectGPR);
     12424
     12425        flushRegisters();
     12426        GPRFlushedCallResult result(this);
     12427        GPRReg resultGPR = result.gpr();
     12428        callOperation(operationObjectKeysObject, resultGPR, objectGPR);
     12429        m_jit.exceptionCheck();
     12430
     12431        cellResult(resultGPR, node);
     12432        break;
     12433    }
     12434
     12435    case UntypedUse: {
     12436        JSValueOperand object(this, node->child1());
     12437
     12438        JSValueRegs objectRegs = object.jsValueRegs();
     12439
     12440        flushRegisters();
     12441        GPRFlushedCallResult result(this);
     12442        GPRReg resultGPR = result.gpr();
     12443        callOperation(operationObjectKeys, resultGPR, objectRegs);
     12444        m_jit.exceptionCheck();
     12445
     12446        cellResult(resultGPR, node);
     12447        break;
     12448    }
     12449
     12450    default:
     12451        RELEASE_ASSERT_NOT_REACHED();
     12452        break;
     12453    }
     12454}
     12455
    1236812456void SpeculativeJIT::compileObjectCreate(Node* node)
    1236912457{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r239231 r239324  
    14801480    void compileNewTypedArray(Node*);
    14811481    void compileToThis(Node*);
     1482    void compileObjectKeys(Node*);
    14821483    void compileObjectCreate(Node*);
    14831484    void compileCreateThis(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r239231 r239324  
    31653165    case ObjectCreate: {
    31663166        compileObjectCreate(node);
     3167        break;
     3168    }
     3169
     3170    case ObjectKeys: {
     3171        compileObjectKeys(node);
    31673172        break;
    31683173    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r239255 r239324  
    34073407    case ObjectCreate: {
    34083408        compileObjectCreate(node);
     3409        break;
     3410    }
     3411
     3412    case ObjectKeys: {
     3413        compileObjectKeys(node);
    34093414        break;
    34103415    }
  • trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

    r239231 r239324  
    117117    macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \
    118118    macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \
     119    macro(Structure_previousOrRareData, Structure::previousOrRareDataOffset()) \
    119120    macro(Structure_prototype, Structure::prototypeOffset()) \
    120121    macro(Structure_structureID, Structure::structureIDOffset()) \
     122    macro(StructureRareData_cachedOwnKeys, StructureRareData::offsetOfCachedOwnKeys()) \
    121123    macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \
    122124    macro(HashMapImpl_buffer,  HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r239231 r239324  
    202202    case CallStringConstructor:
    203203    case ObjectCreate:
     204    case ObjectKeys:
    204205    case MakeRope:
    205206    case NewArrayWithSize:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r239231 r239324  
    867867            compileObjectCreate();
    868868            break;
     869        case ObjectKeys:
     870            compileObjectKeys();
     871            break;
    869872        case NewObject:
    870873            compileNewObject();
     
    54965499        m_out.appendTo(continuation, lastNext);
    54975500        setInt32(m_out.phi(Int32, zeroLengthResult, nonZeroLengthResult));
     5501    }
     5502
     5503    void compileObjectKeys()
     5504    {
     5505        switch (m_node->child1().useKind()) {
     5506        case ObjectUse: {
     5507            if (m_graph.isWatchingHavingABadTimeWatchpoint(m_node)) {
     5508                LBasicBlock notNullCase = m_out.newBlock();
     5509                LBasicBlock rareDataCase = m_out.newBlock();
     5510                LBasicBlock useCacheCase = m_out.newBlock();
     5511                LBasicBlock slowButArrayBufferCase = m_out.newBlock();
     5512                LBasicBlock slowCase = m_out.newBlock();
     5513                LBasicBlock continuation = m_out.newBlock();
     5514
     5515                LValue object = lowObject(m_node->child1());
     5516                LValue structure = loadStructure(object);
     5517                LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData);
     5518                m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase));
     5519
     5520                LBasicBlock lastNext = m_out.appendTo(notNullCase, rareDataCase);
     5521                m_out.branch(
     5522                    m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())),
     5523                    unsure(rareDataCase), unsure(slowCase));
     5524
     5525                m_out.appendTo(rareDataCase, useCacheCase);
     5526                ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1);
     5527                LValue cachedOwnKeys = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedOwnKeys);
     5528                m_out.branch(m_out.belowOrEqual(cachedOwnKeys, m_out.constIntPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))), unsure(slowCase), unsure(useCacheCase));
     5529
     5530                m_out.appendTo(useCacheCase, slowButArrayBufferCase);
     5531                JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
     5532                RegisteredStructure arrayStructure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
     5533                LValue fastArray = allocateObject<JSArray>(arrayStructure, m_out.addPtr(cachedOwnKeys, JSImmutableButterfly::offsetOfData()), slowButArrayBufferCase);
     5534                ValueFromBlock fastResult = m_out.anchor(fastArray);
     5535                m_out.jump(continuation);
     5536
     5537                m_out.appendTo(slowButArrayBufferCase, slowCase);
     5538                LValue slowArray = vmCall(Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, weakStructure(arrayStructure), cachedOwnKeys);
     5539                ValueFromBlock slowButArrayBufferResult = m_out.anchor(slowArray);
     5540                m_out.jump(continuation);
     5541
     5542                m_out.appendTo(slowCase, continuation);
     5543                VM& vm = this->vm();
     5544                LValue slowResultValue = lazySlowPath(
     5545                    [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
     5546                        return createLazyCallGenerator(vm,
     5547                            operationObjectKeysObject, locations[0].directGPR(), locations[1].directGPR());
     5548                    },
     5549                    object);
     5550                ValueFromBlock slowResult = m_out.anchor(slowResultValue);
     5551                m_out.jump(continuation);
     5552
     5553                m_out.appendTo(continuation, lastNext);
     5554                setJSValue(m_out.phi(pointerType(), fastResult, slowButArrayBufferResult, slowResult));
     5555                break;
     5556            }
     5557            setJSValue(vmCall(Int64, m_out.operation(operationObjectKeysObject), m_callFrame, lowObject(m_node->child1())));
     5558            break;
     5559        }
     5560        case UntypedUse:
     5561            setJSValue(vmCall(Int64, m_out.operation(operationObjectKeys), m_callFrame, lowJSValue(m_node->child1())));
     5562            break;
     5563        default:
     5564            RELEASE_ASSERT_NOT_REACHED();
     5565            break;
     5566        }
    54985567    }
    54995568
  • trunk/Source/JavaScriptCore/runtime/Butterfly.h

    r232951 r239324  
    8686        }
    8787
     88        void setStartingValue(JSValue value)
     89        {
     90            m_data.setStartingValue(value);
     91        }
     92
    8893        void clear()
    8994        {
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp

    r239231 r239324  
    120120    case ObjectIsIntrinsic:
    121121        return "ObjectIsIntrinsic";
     122    case ObjectKeysIntrinsic:
     123        return "ObjectKeysIntrinsic";
    122124    case ReflectGetPrototypeOfIntrinsic:
    123125        return "ReflectGetPrototypeOfIntrinsic";
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r239231 r239324  
    7373    ObjectGetPrototypeOfIntrinsic,
    7474    ObjectIsIntrinsic,
     75    ObjectKeysIntrinsic,
    7576    ReflectGetPrototypeOfIntrinsic,
    7677    StringPrototypeValueOfIntrinsic,
  • trunk/Source/JavaScriptCore/runtime/JSImmutableButterfly.h

    r239231 r239324  
    121121        m_header.setVectorLength(length);
    122122        m_header.setPublicLength(length);
     123        if (hasContiguous(indexingType())) {
     124            for (unsigned index = 0; index < length; ++index)
     125                toButterfly()->contiguous().at(this, index).setStartingValue(JSValue());
     126        }
    123127    }
    124128
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r239231 r239324  
    3131#include "JSGlobalObject.h"
    3232#include "JSGlobalObjectFunctions.h"
     33#include "JSImmutableButterfly.h"
    3334#include "Lookup.h"
    3435#include "ObjectPrototype.h"
     
    7475  getOwnPropertyNames       objectConstructorGetOwnPropertyNames        DontEnum|Function 1
    7576  getOwnPropertySymbols     objectConstructorGetOwnPropertySymbols      DontEnum|Function 1
    76   keys                      objectConstructorKeys                       DontEnum|Function 1
     77  keys                      objectConstructorKeys                       DontEnum|Function 1 ObjectKeysIntrinsic
    7778  defineProperty            objectConstructorDefineProperty             DontEnum|Function 3
    7879  defineProperties          objectConstructorDefineProperties           DontEnum|Function 2
     
    272273}
    273274
    274 // FIXME: Use the enumeration cache.
    275275EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
    276276{
     
    893893}
    894894
    895 // FIXME: Use the enumeration cache.
    896895JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode)
    897896{
    898897    VM& vm = exec->vm();
    899898    auto scope = DECLARE_THROW_SCOPE(vm);
     899
     900    auto* globalObject = exec->lexicalGlobalObject();
     901    bool isObjectKeys = propertyNameMode == PropertyNameMode::Strings && dontEnumPropertiesMode == DontEnumPropertiesMode::Exclude;
     902    // We attempt to look up own property keys cache in Object.keys case.
     903    if (isObjectKeys) {
     904        if (LIKELY(!globalObject->isHavingABadTime())) {
     905            if (auto* immutableButterfly = object->structure(vm)->cachedOwnKeys()) {
     906                Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode());
     907                return JSArray::createWithButterfly(vm, nullptr, arrayStructure, immutableButterfly->toButterfly());
     908            }
     909        }
     910    }
     911
    900912    PropertyNameArray properties(&vm, propertyNameMode, PrivateSymbolMode::Exclude);
    901913    object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
     
    919931        ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols);
    920932        if (!mustFilterProperty && properties.size() < MIN_SPARSE_ARRAY_INDEX) {
    921             auto* globalObject = exec->lexicalGlobalObject();
    922933            if (LIKELY(!globalObject->isHavingABadTime())) {
     934                if (isObjectKeys) {
     935                    Structure* structure = object->structure(vm);
     936                    if (structure->canCacheOwnKeys()) {
     937                        auto* cachedButterfly = structure->cachedOwnKeysIgnoringSentinel();
     938                        if (cachedButterfly == StructureRareData::cachedOwnKeysSentinel()) {
     939                            size_t numProperties = properties.size();
     940                            auto* newButterfly = JSImmutableButterfly::create(vm, CopyOnWriteArrayWithContiguous, numProperties);
     941                            for (size_t i = 0; i < numProperties; i++) {
     942                                const auto& identifier = properties[i];
     943                                ASSERT(!identifier.isSymbol());
     944                                newButterfly->setIndex(vm, i, jsOwnedString(&vm, identifier.string()));
     945                            }
     946
     947                            structure->setCachedOwnKeys(vm, newButterfly);
     948                            Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(newButterfly->indexingMode());
     949                            return JSArray::createWithButterfly(vm, nullptr, arrayStructure, newButterfly->toButterfly());
     950                        }
     951
     952                        if (cachedButterfly == nullptr)
     953                            structure->setCachedOwnKeys(vm, StructureRareData::cachedOwnKeysSentinel());
     954                    }
     955                }
     956
    923957                size_t numProperties = properties.size();
    924958                JSArray* keys = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), numProperties);
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r239231 r239324  
    12531253bool Structure::canCachePropertyNameEnumerator() const
    12541254{
    1255     auto canCache = [] (const Structure* structure) {
    1256         if (structure->isDictionary())
    1257             return false;
    1258         if (hasIndexedProperties(structure->indexingType()))
    1259             return false;
    1260         if (structure->typeInfo().overridesGetPropertyNames())
    1261             return false;
    1262         return true;
    1263     };
    1264 
    1265     if (!canCache(this))
     1255    if (!this->canCacheOwnKeys())
    12661256        return false;
    12671257
     
    12721262        if (!structure->get())
    12731263            return true;
    1274         if (!canCache(structure->get()))
     1264        if (!structure->get()->canCacheOwnKeys())
    12751265            return false;
    12761266        structure++;
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r239231 r239324  
    3939#include "StructureIDBlob.h"
    4040#include "StructureRareData.h"
    41 #include "StructureRareDataInlines.h"
    4241#include "StructureTransitionTable.h"
    4342#include "JSTypeInfo.h"
     
    327326    }
    328327
     328    const StructureRareData* rareDataConcurrently() const
     329    {
     330        JSCell* cell = m_previousOrRareData.get();
     331        if (isRareData(cell))
     332            return static_cast<StructureRareData*>(cell);
     333        return nullptr;
     334    }
     335
    329336    StructureRareData* ensureRareData(VM& vm)
    330337    {
     
    473480    bool canAccessPropertiesQuicklyForEnumeration() const;
    474481
     482    void setCachedOwnKeys(VM&, JSImmutableButterfly*);
     483    JSImmutableButterfly* cachedOwnKeys() const;
     484    JSImmutableButterfly* cachedOwnKeysIgnoringSentinel() const;
     485    bool canCacheOwnKeys() const;
     486
    475487    void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
    476488
     
    519531    {
    520532        return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
     533    }
     534
     535    static ptrdiff_t previousOrRareDataOffset()
     536    {
     537        return OBJECT_OFFSETOF(Structure, m_previousOrRareData);
    521538    }
    522539
  • trunk/Source/JavaScriptCore/runtime/StructureInlines.h

    r239231 r239324  
    220220}
    221221
     222inline void Structure::setCachedOwnKeys(VM& vm, JSImmutableButterfly* ownKeys)
     223{
     224    ensureRareData(vm)->setCachedOwnKeys(vm, ownKeys);
     225}
     226
     227inline JSImmutableButterfly* Structure::cachedOwnKeys() const
     228{
     229    if (!hasRareData())
     230        return nullptr;
     231    return rareData()->cachedOwnKeys();
     232}
     233
     234inline JSImmutableButterfly* Structure::cachedOwnKeysIgnoringSentinel() const
     235{
     236    if (!hasRareData())
     237        return nullptr;
     238    return rareData()->cachedOwnKeysIgnoringSentinel();
     239}
     240
     241inline bool Structure::canCacheOwnKeys() const
     242{
     243    if (isDictionary())
     244        return false;
     245    if (hasIndexedProperties(indexingType()))
     246        return false;
     247    if (typeInfo().overridesGetPropertyNames())
     248        return false;
     249    return true;
     250}
     251
    222252ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure)
    223253{
  • trunk/Source/JavaScriptCore/runtime/StructureRareData.cpp

    r239231 r239324  
    2828
    2929#include "AdaptiveInferredPropertyValueWatchpointBase.h"
     30#include "JSImmutableButterfly.h"
    3031#include "JSPropertyNameEnumerator.h"
    3132#include "JSString.h"
     
    7172    visitor.append(thisObject->m_objectToStringValue);
    7273    visitor.append(thisObject->m_cachedPropertyNameEnumerator);
    73 }
    74 
    75 JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
    76 {
    77     return m_cachedPropertyNameEnumerator.get();
    78 }
    79 
    80 void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
    81 {
    82     m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
     74    if (thisObject->m_cachedOwnKeys.unvalidatedGet() != cachedOwnKeysSentinel())
     75        visitor.append(thisObject->m_cachedOwnKeys);
    8376}
    8477
  • trunk/Source/JavaScriptCore/runtime/StructureRareData.h

    r239231 r239324  
    5959    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
    6060
    61     Structure* previousID() const;
     61    Structure* previousID() const
     62    {
     63        return m_previous.get();
     64    }
    6265    void setPreviousID(VM&, Structure*);
    6366    void clearPreviousID();
     
    6972    void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
    7073
     74    JSImmutableButterfly* cachedOwnKeys() const;
     75    JSImmutableButterfly* cachedOwnKeysIgnoringSentinel() const;
     76    JSImmutableButterfly* cachedOwnKeysConcurrently() const;
     77    void setCachedOwnKeys(VM&, JSImmutableButterfly*);
     78
    7179    Box<InlineWatchpointSet> copySharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
    7280    const Box<InlineWatchpointSet>& sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
    7381    void setSharedPolyProtoWatchpoint(Box<InlineWatchpointSet>&& sharedPolyProtoWatchpoint) { m_polyProtoWatchpoint = WTFMove(sharedPolyProtoWatchpoint); }
    7482    bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); }
     83
     84    static JSImmutableButterfly* cachedOwnKeysSentinel() { return bitwise_cast<JSImmutableButterfly*>(static_cast<uintptr_t>(1)); }
     85
     86    static ptrdiff_t offsetOfCachedOwnKeys()
     87    {
     88        return OBJECT_OFFSETOF(StructureRareData, m_cachedOwnKeys);
     89    }
    7590
    7691    DECLARE_EXPORT_INFO;
     
    87102    WriteBarrier<Structure> m_previous;
    88103    WriteBarrier<JSString> m_objectToStringValue;
     104    // FIXME: We should have some story for clearing these property names caches in GC.
     105    // https://bugs.webkit.org/show_bug.cgi?id=192659
    89106    WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator;
     107    WriteBarrier<JSImmutableButterfly> m_cachedOwnKeys;
    90108
    91109    typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
  • trunk/Source/JavaScriptCore/runtime/StructureRareDataInlines.h

    r239231 r239324  
    2626#pragma once
    2727
     28#include "JSImmutableButterfly.h"
     29#include "JSPropertyNameEnumerator.h"
    2830#include "JSString.h"
    2931#include "StructureRareData.h"
    3032
    3133namespace JSC {
    32 
    33 inline Structure* StructureRareData::previousID() const
    34 {
    35     return m_previous.get();
    36 }
    3734
    3835inline void StructureRareData::setPreviousID(VM& vm, Structure* structure)
     
    5148}
    5249
     50inline JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
     51{
     52    return m_cachedPropertyNameEnumerator.get();
     53}
     54
     55inline void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
     56{
     57    m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
     58}
     59
     60inline JSImmutableButterfly* StructureRareData::cachedOwnKeys() const
     61{
     62    ASSERT(!isCompilationThread());
     63    auto* butterfly = m_cachedOwnKeys.unvalidatedGet();
     64    if (butterfly == cachedOwnKeysSentinel())
     65        return nullptr;
     66    return butterfly;
     67}
     68
     69inline JSImmutableButterfly* StructureRareData::cachedOwnKeysIgnoringSentinel() const
     70{
     71    ASSERT(!isCompilationThread());
     72    return m_cachedOwnKeys.unvalidatedGet();
     73}
     74
     75inline JSImmutableButterfly* StructureRareData::cachedOwnKeysConcurrently() const
     76{
     77    auto* butterfly = m_cachedOwnKeys.unvalidatedGet();
     78    if (butterfly == cachedOwnKeysSentinel())
     79        return nullptr;
     80    return butterfly;
     81}
     82
     83inline void StructureRareData::setCachedOwnKeys(VM& vm, JSImmutableButterfly* butterfly)
     84{
     85    if (butterfly == cachedOwnKeysSentinel()) {
     86        m_cachedOwnKeys.setWithoutWriteBarrier(butterfly);
     87        return;
     88    }
     89
     90    WTF::storeStoreFence();
     91    m_cachedOwnKeys.set(vm, this, butterfly);
     92}
     93
    5394} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r239231 r239324  
    435435    promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
    436436    internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull()));
     437    nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
    437438    programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull()));
    438439    moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
     
    449450    sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this));
    450451
    451     nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
    452452    smallStrings.initializeCommonStrings(*this);
    453453
Note: See TracChangeset for help on using the changeset viewer.