Ignore:
Timestamp:
Dec 17, 2018, 10:54:49 PM (6 years ago)
Author:
[email protected]
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):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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{
Note: See TracChangeset for help on using the changeset viewer.