Diff
Modified: trunk/JSTests/ChangeLog (239152 => 239153)
--- trunk/JSTests/ChangeLog 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/JSTests/ChangeLog 2018-12-13 07:13:38 UTC (rev 239153)
@@ -1,3 +1,30 @@
+2018-12-10 Yusuke Suzuki <yusukesuz...@slowstart.org>
+
+ [JSC] Optimize Object.keys by caching own keys results in StructureRareData
+ https://bugs.webkit.org/show_bug.cgi?id=190047
+
+ Reviewed by Keith Miller.
+
+ * 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):
+
2018-12-12 Yusuke Suzuki <yusukesuz...@slowstart.org>
[DFG][FTL] Add NewSymbol
Added: trunk/JSTests/stress/object-keys-cached-zero.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-cached-zero.js (rev 0)
+++ trunk/JSTests/stress/object-keys-cached-zero.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,21 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+var object = {};
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 0);
+ shouldBe(result[0], undefined);
+ result[0] = i;
+ shouldBe(result.length, 1);
+ shouldBe(result[0], i);
+}
Added: trunk/JSTests/stress/object-keys-changed-attribute.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-changed-attribute.js (rev 0)
+++ trunk/JSTests/stress/object-keys-changed-attribute.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,28 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+var object = { Cocoa: 42 };
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 1);
+ shouldBe(result[0], 'Cocoa');
+}
+
+Reflect.defineProperty(object, 'Cocoa', {
+ enumerable: false
+});
+
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 0);
+ shouldBe(result[0], undefined);
+}
Added: trunk/JSTests/stress/object-keys-changed-index.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-changed-index.js (rev 0)
+++ trunk/JSTests/stress/object-keys-changed-index.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,28 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+var object = {};
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 0);
+ shouldBe(result[0], undefined);
+ result[0] = i;
+ shouldBe(result.length, 1);
+ shouldBe(result[0], i);
+}
+
+object[0] = 42;
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 1);
+ shouldBe(result[0], '0');
+}
Added: trunk/JSTests/stress/object-keys-changed.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-changed.js (rev 0)
+++ trunk/JSTests/stress/object-keys-changed.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,28 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+var object = {};
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 0);
+ shouldBe(result[0], undefined);
+ result[0] = i;
+ shouldBe(result.length, 1);
+ shouldBe(result[0], i);
+}
+
+object.Cocoa = 42;
+for (var i = 0; i < 1e6; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 1);
+ shouldBe(result[0], 'Cocoa');
+}
Added: trunk/JSTests/stress/object-keys-indexed-non-cache.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-indexed-non-cache.js (rev 0)
+++ trunk/JSTests/stress/object-keys-indexed-non-cache.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,25 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+var object = {0: 42};
+for (var i = 0; i < 1e3; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 1);
+ shouldBe(result[0], '0');
+}
+object[1] = 44;
+for (var i = 0; i < 1e3; ++i) {
+ var result = test(object);
+ shouldBe(result.length, 2);
+ shouldBe(result[0], '0');
+ shouldBe(result[1], '1');
+}
Added: trunk/JSTests/stress/object-keys-overrides-get-property-names.js (0 => 239153)
--- trunk/JSTests/stress/object-keys-overrides-get-property-names.js (rev 0)
+++ trunk/JSTests/stress/object-keys-overrides-get-property-names.js 2018-12-13 07:13:38 UTC (rev 239153)
@@ -0,0 +1,57 @@
+function shouldBe(actual, expected)
+{
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object)
+{
+ return Object.keys(object);
+}
+noInline(test);
+
+{
+ let object = new String("Cocoa");
+ for (let i = 0; i < 1e3; ++i) {
+ let result = test(object);
+ shouldBe(result.length, 5);
+ shouldBe(result[0], '0');
+ shouldBe(result[1], '1');
+ shouldBe(result[2], '2');
+ shouldBe(result[3], '3');
+ shouldBe(result[4], '4');
+ }
+
+ object.Cocoa = 42;
+ let result = test(object);
+ shouldBe(result.length, 6);
+ shouldBe(result[0], '0');
+ shouldBe(result[1], '1');
+ shouldBe(result[2], '2');
+ shouldBe(result[3], '3');
+ shouldBe(result[4], '4');
+ shouldBe(result[5], 'Cocoa');
+}
+
+{
+ let object = new String("Cocoa");
+ for (let i = 0; i < 1e3; ++i) {
+ let result = test(object);
+ shouldBe(result.length, 5);
+ shouldBe(result[0], '0');
+ shouldBe(result[1], '1');
+ shouldBe(result[2], '2');
+ shouldBe(result[3], '3');
+ shouldBe(result[4], '4');
+ }
+
+ object[8] = 42;
+ let result = test(object);
+ shouldBe(result.length, 6);
+ shouldBe(result[0], '0');
+ shouldBe(result[1], '1');
+ shouldBe(result[2], '2');
+ shouldBe(result[3], '3');
+ shouldBe(result[4], '4');
+ shouldBe(result[5], '8');
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (239152 => 239153)
--- trunk/Source/_javascript_Core/ChangeLog 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-12-13 07:13:38 UTC (rev 239153)
@@ -1,3 +1,96 @@
+2018-12-10 Yusuke Suzuki <yusukesuz...@slowstart.org>
+
+ [JSC] Optimize Object.keys by caching own keys results in StructureRareData
+ https://bugs.webkit.org/show_bug.cgi?id=190047
+
+ Reviewed by Keith Miller.
+
+ 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/Intrinsic.cpp:
+ (JSC::intrinsicName):
+ * runtime/Intrinsic.h:
+ * runtime/JSImmutableButterfly.h:
+ (JSC::JSImmutableButterfly::createSentinel):
+ * 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::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::cachedOwnKeysConcurrently const):
+ (JSC::StructureRareData::setCachedOwnKeys):
+ (JSC::StructureRareData::previousID const): Deleted.
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+
2018-12-12 Yusuke Suzuki <yusukesuz...@slowstart.org>
[DFG][FTL] Add NewSymbol
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -43,6 +43,7 @@
#include "Operations.h"
#include "PutByIdStatus.h"
#include "StringObject.h"
+#include "StructureRareDataInlines.h"
#include <wtf/BooleanLattice.h>
#include <wtf/CheckedArithmetic.h>
@@ -2575,6 +2576,30 @@
break;
}
+ case ObjectKeys: {
+ if (node->child1().useKind() == ObjectUse) {
+ auto& structureSet = forNode(node->child1()).m_structure;
+ if (structureSet.isFinite() && structureSet.size() == 1) {
+ RegisteredStructure structure = structureSet.onlyStructure();
+ if (auto* rareData = structure->rareDataConcurrently()) {
+ auto* immutableButterfly = rareData->cachedOwnKeysConcurrently();
+ if (immutableButterfly && immutableButterfly != m_vm.sentinelImmutableButterfly.get()) {
+ if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+ m_state.setFoundConstants(true);
+ didFoldClobberWorld();
+ setTypeForNode(node, SpecArray);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ clobberWorld();
+ setTypeForNode(node, SpecArray);
+ break;
+ }
+
case ToObject:
case CallObjectConstructor: {
AbstractValue& source = forNode(node->child1());
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -2688,6 +2688,15 @@
return true;
}
+ case ObjectKeysIntrinsic: {
+ if (argumentCountIncludingThis < 2)
+ return false;
+
+ insertChecks();
+ set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset))));
+ return true;
+ }
+
case ReflectGetPrototypeOfIntrinsic: {
if (argumentCountIncludingThis != 2)
return false;
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -667,6 +667,7 @@
case CreateThis:
case InstanceOf:
case StringValueOf:
+ case ObjectKeys:
read(World);
write(Heap);
return;
@@ -1528,7 +1529,6 @@
}
}
-
case NewObject:
case NewRegexp:
case NewSymbol:
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -766,6 +766,26 @@
break;
}
+ case ObjectKeys: {
+ if (node->child1().useKind() == ObjectUse) {
+ auto& structureSet = m_state.forNode(node->child1()).m_structure;
+ if (structureSet.isFinite() && structureSet.size() == 1) {
+ RegisteredStructure structure = structureSet.onlyStructure();
+ if (auto* rareData = structure->rareDataConcurrently()) {
+ auto* immutableButterfly = rareData->cachedOwnKeysConcurrently();
+ if (immutableButterfly && immutableButterfly != m_graph.m_vm.sentinelImmutableButterfly.get()) {
+ if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+ node->convertToNewArrayBuffer(m_graph.freeze(immutableButterfly));
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
case ToNumber: {
if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber)
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -338,6 +338,7 @@
case ToThis:
case CreateThis:
case ObjectCreate:
+ case ObjectKeys:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
case Arrayify:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -1575,6 +1575,14 @@
break;
}
+ case ObjectKeys: {
+ if (node->child1()->shouldSpeculateObject()) {
+ watchHavingABadTime(node);
+ fixEdge<ObjectUse>(node->child1());
+ }
+ break;
+ }
+
case CheckStringIdent: {
fixEdge<StringIdentUse>(node->child1());
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGNode.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -31,6 +31,7 @@
#include "DFGGraph.h"
#include "DFGPromotedHeapLocation.h"
#include "JSCInlines.h"
+#include "JSImmutableButterfly.h"
namespace JSC { namespace DFG {
@@ -223,6 +224,17 @@
children.reset();
}
+void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly)
+{
+ setOpAndDefaultFlags(NewArrayBuffer);
+ NewArrayBufferData data { };
+ data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode();
+ data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength();
+ children.reset();
+ m_opInfo = immutableButterfly;
+ m_opInfo2 = data.asQuadWord;
+}
+
void Node::convertToDirectCall(FrozenValue* executable)
{
NodeType newOp = LastNodeType;
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -761,6 +761,8 @@
m_opInfo = structure;
m_opInfo2 = OpInfoWrapper();
}
+
+ void convertToNewArrayBuffer(FrozenValue* immutableButterfly);
void convertToDirectCall(FrozenValue*);
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -264,6 +264,7 @@
macro(ParseInt, NodeMustGenerate | NodeResultJS) \
macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \
macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \
+ macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \
\
/* Atomics object functions. */\
macro(AtomicsAdd, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -248,6 +248,25 @@
return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode));
}
+JSArray* JIT_OPERATION operationObjectKeys(ExecState* exec, EncodedJSValue encodedObject)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSObject* object = JSValue::decode(encodedObject).toObject(exec);
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ scope.release();
+ return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
+}
+
+JSArray* JIT_OPERATION operationObjectKeysObject(ExecState* exec, JSObject* object)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude);
+}
+
JSCell* JIT_OPERATION operationObjectCreate(ExecState* exec, EncodedJSValue encodedPrototype)
{
VM& vm = exec->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -43,6 +43,8 @@
// These routines provide callbacks out to C++ implementations of operations too complex to JIT.
JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget) WTF_INTERNAL;
JSCell* JIT_OPERATION operationToObject(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget, UniquedStringImpl*) WTF_INTERNAL;
+JSArray* JIT_OPERATION operationObjectKeys(ExecState*, EncodedJSValue) WTF_INTERNAL;
+JSArray* JIT_OPERATION operationObjectKeysObject(ExecState*, JSObject*) WTF_INTERNAL;
JSCell* JIT_OPERATION operationObjectCreate(ExecState*, EncodedJSValue) WTF_INTERNAL;
JSCell* JIT_OPERATION operationObjectCreateObject(ExecState*, JSObject*) WTF_INTERNAL;
JSCell* JIT_OPERATION operationCreateThis(ExecState*, JSObject* constructor, uint32_t inlineCapacity) WTF_INTERNAL;
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -975,7 +975,8 @@
case NewArray:
case NewArrayWithSize:
case CreateRest:
- case NewArrayBuffer: {
+ case NewArrayBuffer:
+ case ObjectKeys: {
setPrediction(SpecArray);
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -178,6 +178,7 @@
case ToThis:
case CreateThis:
case ObjectCreate:
+ case ObjectKeys:
case GetCallee:
case SetCallee:
case GetArgumentCountIncludingThis:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -12345,6 +12345,94 @@
jsValueResult(tempRegs, node);
}
+void SpeculativeJIT::compileObjectKeys(Node* node)
+{
+ switch (node->child1().useKind()) {
+ case ObjectUse: {
+ if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+ SpeculateCellOperand object(this, node->child1());
+ GPRTemporary structure(this);
+ GPRTemporary scratch(this);
+ GPRTemporary scratch2(this);
+ GPRTemporary scratch3(this);
+ GPRTemporary result(this);
+
+ GPRReg objectGPR = object.gpr();
+ GPRReg structureGPR = structure.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+ GPRReg scratch2GPR = scratch2.gpr();
+ GPRReg scratch3GPR = scratch3.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ speculateObject(node->child1(), objectGPR);
+
+ CCallHelpers::JumpList slowCases;
+ m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR);
+ m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
+
+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
+ slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID()))));
+
+ m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR);
+
+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
+ slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, scratchGPR, TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelImmutableButterfly.get())));
+
+ MacroAssembler::JumpList slowButArrayBufferCases;
+
+ JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
+ RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
+
+ m_jit.move(scratchGPR, scratch3GPR);
+ m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR);
+
+ emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases);
+
+ addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR));
+
+ addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR));
+
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ SpeculateCellOperand object(this, node->child1());
+
+ GPRReg objectGPR = object.gpr();
+
+ speculateObject(node->child1(), objectGPR);
+
+ flushRegisters();
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+ callOperation(operationObjectKeysObject, resultGPR, objectGPR);
+ m_jit.exceptionCheck();
+
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ case UntypedUse: {
+ JSValueOperand object(this, node->child1());
+
+ JSValueRegs objectRegs = object.jsValueRegs();
+
+ flushRegisters();
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+ callOperation(operationObjectKeys, resultGPR, objectRegs);
+ m_jit.exceptionCheck();
+
+ cellResult(resultGPR, node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
void SpeculativeJIT::compileObjectCreate(Node* node)
{
switch (node->child1().useKind()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -1478,6 +1478,7 @@
void compileNewArrayWithSize(Node*);
void compileNewTypedArray(Node*);
void compileToThis(Node*);
+ void compileObjectKeys(Node*);
void compileObjectCreate(Node*);
void compileCreateThis(Node*);
void compileNewObject(Node*);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -3162,6 +3162,11 @@
break;
}
+ case ObjectKeys: {
+ compileObjectKeys(node);
+ break;
+ }
+
case CreateThis: {
compileCreateThis(node);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -3404,6 +3404,11 @@
break;
}
+ case ObjectKeys: {
+ compileObjectKeys(node);
+ break;
+ }
+
case CreateThis: {
compileCreateThis(node);
break;
Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (239152 => 239153)
--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -116,8 +116,10 @@
macro(Structure_globalObject, Structure::globalObjectOffset()) \
macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \
macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \
+ macro(Structure_previousOrRareData, Structure::previousOrRareDataOffset()) \
macro(Structure_prototype, Structure::prototypeOffset()) \
macro(Structure_structureID, Structure::structureIDOffset()) \
+ macro(StructureRareData_cachedOwnKeys, StructureRareData::offsetOfCachedOwnKeys()) \
macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \
macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \
macro(HashMapImpl_head, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()) \
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -200,6 +200,7 @@
case CallObjectConstructor:
case CallStringConstructor:
case ObjectCreate:
+ case ObjectKeys:
case MakeRope:
case NewArrayWithSize:
case TryGetById:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -863,6 +863,9 @@
case ObjectCreate:
compileObjectCreate();
break;
+ case ObjectKeys:
+ compileObjectKeys();
+ break;
case NewObject:
compileNewObject();
break;
@@ -5485,6 +5488,75 @@
setInt32(m_out.phi(Int32, zeroLengthResult, nonZeroLengthResult));
}
+ void compileObjectKeys()
+ {
+ switch (m_node->child1().useKind()) {
+ case ObjectUse: {
+ if (m_graph.isWatchingHavingABadTimeWatchpoint(m_node)) {
+ LBasicBlock notNullCase = m_out.newBlock();
+ LBasicBlock rareDataCase = m_out.newBlock();
+ LBasicBlock notNullCacheCase = m_out.newBlock();
+ LBasicBlock useCacheCase = m_out.newBlock();
+ LBasicBlock slowButArrayBufferCase = m_out.newBlock();
+ LBasicBlock slowCase = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ LValue object = lowObject(m_node->child1());
+ LValue structure = loadStructure(object);
+ LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData);
+ m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase));
+
+ LBasicBlock lastNext = m_out.appendTo(notNullCase, rareDataCase);
+ m_out.branch(
+ m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())),
+ unsure(rareDataCase), unsure(slowCase));
+
+ m_out.appendTo(rareDataCase, notNullCacheCase);
+ LValue cachedOwnKeys = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedOwnKeys);
+ m_out.branch(m_out.notNull(cachedOwnKeys), unsure(notNullCacheCase), unsure(slowCase));
+
+ m_out.appendTo(notNullCacheCase, useCacheCase);
+ m_out.branch(m_out.notEqual(cachedOwnKeys, weakPointer(m_graph.m_vm.sentinelImmutableButterfly.get())), unsure(useCacheCase), unsure(slowCase));
+
+ m_out.appendTo(useCacheCase, slowButArrayBufferCase);
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+ RegisteredStructure arrayStructure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous));
+ LValue fastArray = allocateObject<JSArray>(arrayStructure, m_out.addPtr(cachedOwnKeys, JSImmutableButterfly::offsetOfData()), slowButArrayBufferCase);
+ ValueFromBlock fastResult = m_out.anchor(fastArray);
+ m_out.jump(continuation);
+
+ m_out.appendTo(slowButArrayBufferCase, slowCase);
+ LValue slowArray = vmCall(Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, weakStructure(arrayStructure), cachedOwnKeys);
+ ValueFromBlock slowButArrayBufferResult = m_out.anchor(slowArray);
+ m_out.jump(continuation);
+
+ m_out.appendTo(slowCase, continuation);
+ VM& vm = this->vm();
+ LValue slowResultValue = lazySlowPath(
+ [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
+ return createLazyCallGenerator(vm,
+ operationObjectKeysObject, locations[0].directGPR(), locations[1].directGPR());
+ },
+ object);
+ ValueFromBlock slowResult = m_out.anchor(slowResultValue);
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(pointerType(), fastResult, slowButArrayBufferResult, slowResult));
+ break;
+ }
+ setJSValue(vmCall(Int64, m_out.operation(operationObjectKeysObject), m_callFrame, lowObject(m_node->child1())));
+ break;
+ }
+ case UntypedUse:
+ setJSValue(vmCall(Int64, m_out.operation(operationObjectKeys), m_callFrame, lowJSValue(m_node->child1())));
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
void compileObjectCreate()
{
switch (m_node->child1().useKind()) {
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -119,6 +119,8 @@
return "ObjectGetPrototypeOfIntrinsic";
case ObjectIsIntrinsic:
return "ObjectIsIntrinsic";
+ case ObjectKeysIntrinsic:
+ return "ObjectKeysIntrinsic";
case ReflectGetPrototypeOfIntrinsic:
return "ReflectGetPrototypeOfIntrinsic";
case StringPrototypeValueOfIntrinsic:
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -72,6 +72,7 @@
ObjectCreateIntrinsic,
ObjectGetPrototypeOfIntrinsic,
ObjectIsIntrinsic,
+ ObjectKeysIntrinsic,
ReflectGetPrototypeOfIntrinsic,
StringPrototypeValueOfIntrinsic,
StringPrototypeReplaceIntrinsic,
Modified: trunk/Source/_javascript_Core/runtime/JSImmutableButterfly.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/JSImmutableButterfly.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/JSImmutableButterfly.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -67,6 +67,11 @@
return array;
}
+ static JSImmutableButterfly* createSentinel(VM& vm)
+ {
+ return create(vm, CopyOnWriteArrayWithContiguous, 0);
+ }
+
unsigned publicLength() const { return m_header.publicLength(); }
unsigned vectorLength() const { return m_header.vectorLength(); }
unsigned length() const { return m_header.publicLength(); }
Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -30,6 +30,7 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSGlobalObjectFunctions.h"
+#include "JSImmutableButterfly.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
#include "PropertyDescriptor.h"
@@ -73,7 +74,7 @@
getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors DontEnum|Function 1
getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
getOwnPropertySymbols objectConstructorGetOwnPropertySymbols DontEnum|Function 1
- keys objectConstructorKeys DontEnum|Function 1
+ keys objectConstructorKeys DontEnum|Function 1 ObjectKeysIntrinsic
defineProperty objectConstructorDefineProperty DontEnum|Function 3
defineProperties objectConstructorDefineProperties DontEnum|Function 2
create objectConstructorCreate DontEnum|Function 2 ObjectCreateIntrinsic
@@ -271,7 +272,6 @@
RELEASE_AND_RETURN(scope, JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include)));
}
-// FIXME: Use the enumeration cache.
EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
{
VM& vm = exec->vm();
@@ -892,11 +892,25 @@
return JSValue::encode(jsBoolean(sameValue(exec, exec->argument(0), exec->argument(1))));
}
-// FIXME: Use the enumeration cache.
JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* globalObject = exec->lexicalGlobalObject();
+ bool isObjectKeys = propertyNameMode == PropertyNameMode::Strings && dontEnumPropertiesMode == DontEnumPropertiesMode::Exclude;
+ // We attempt to look up own property keys cache in Object.keys case.
+ if (isObjectKeys) {
+ if (LIKELY(!globalObject->isHavingABadTime())) {
+ if (auto* immutableButterfly = object->structure(vm)->cachedOwnKeys()) {
+ if (immutableButterfly != vm.sentinelImmutableButterfly.get()) {
+ Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode());
+ return JSArray::createWithButterfly(vm, nullptr, arrayStructure, immutableButterfly->toButterfly());
+ }
+ }
+ }
+ }
+
PropertyNameArray properties(&vm, propertyNameMode, PrivateSymbolMode::Exclude);
object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
RETURN_IF_EXCEPTION(scope, nullptr);
@@ -918,8 +932,31 @@
if (propertyNameMode != PropertyNameMode::StringsAndSymbols) {
ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols);
if (!mustFilterProperty && properties.size() < MIN_SPARSE_ARRAY_INDEX) {
- auto* globalObject = exec->lexicalGlobalObject();
if (LIKELY(!globalObject->isHavingABadTime())) {
+ if (isObjectKeys) {
+ Structure* structure = object->structure(vm);
+ if (structure->canCacheOwnKeys()) {
+ auto* cachedButterfly = structure->cachedOwnKeys();
+ if (cachedButterfly == vm.sentinelImmutableButterfly.get()) {
+ // Cache the immutable butterfly!
+ size_t numProperties = properties.size();
+ auto* newButterfly = JSImmutableButterfly::create(vm, CopyOnWriteArrayWithContiguous, numProperties);
+ for (size_t i = 0; i < numProperties; i++) {
+ const auto& identifier = properties[i];
+ ASSERT(!identifier.isSymbol());
+ newButterfly->setIndex(vm, i, jsOwnedString(&vm, identifier.string()));
+ }
+
+ structure->setCachedOwnKeys(vm, newButterfly);
+ Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(newButterfly->indexingMode());
+ return JSArray::createWithButterfly(vm, nullptr, arrayStructure, newButterfly->toButterfly());
+ }
+
+ if (cachedButterfly == nullptr)
+ structure->setCachedOwnKeys(vm, jsCast<JSImmutableButterfly*>(vm.sentinelImmutableButterfly.get()));
+ }
+ }
+
size_t numProperties = properties.size();
JSArray* keys = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), numProperties);
WriteBarrier<Unknown>* buffer = keys->butterfly()->contiguous().data();
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -1252,17 +1252,7 @@
bool Structure::canCachePropertyNameEnumerator() const
{
- auto canCache = [] (const Structure* structure) {
- if (structure->isDictionary())
- return false;
- if (hasIndexedProperties(structure->indexingType()))
- return false;
- if (structure->typeInfo().overridesGetPropertyNames())
- return false;
- return true;
- };
-
- if (!canCache(this))
+ if (!this->canCacheOwnKeys())
return false;
StructureChain* structureChain = m_cachedPrototypeChain.get();
@@ -1271,7 +1261,7 @@
while (true) {
if (!structure->get())
return true;
- if (!canCache(structure->get()))
+ if (!structure->get()->canCacheOwnKeys())
return false;
structure++;
}
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -38,7 +38,6 @@
#include "PutPropertySlot.h"
#include "StructureIDBlob.h"
#include "StructureRareData.h"
-#include "StructureRareDataInlines.h"
#include "StructureTransitionTable.h"
#include "JSTypeInfo.h"
#include "Watchpoint.h"
@@ -326,6 +325,15 @@
return static_cast<const StructureRareData*>(m_previousOrRareData.get());
}
+ const StructureRareData* rareDataConcurrently() const
+ {
+ JSCell* cell = m_previousOrRareData.get();
+ WTF::loadLoadFence();
+ if (isRareData(cell))
+ return static_cast<StructureRareData*>(cell);
+ return nullptr;
+ }
+
StructureRareData* ensureRareData(VM& vm)
{
if (!hasRareData())
@@ -472,6 +480,10 @@
bool canCachePropertyNameEnumerator() const;
bool canAccessPropertiesQuicklyForEnumeration() const;
+ void setCachedOwnKeys(VM&, JSImmutableButterfly*);
+ JSImmutableButterfly* cachedOwnKeys() const;
+ bool canCacheOwnKeys() const;
+
void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
JSString* objectToStringValue()
@@ -520,6 +532,11 @@
return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
}
+ static ptrdiff_t previousOrRareDataOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_previousOrRareData);
+ }
+
static Structure* createStructure(VM&);
bool transitionWatchpointSetHasBeenInvalidated() const
Modified: trunk/Source/_javascript_Core/runtime/StructureInlines.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/StructureInlines.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/StructureInlines.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -219,6 +219,29 @@
return false;
}
+inline void Structure::setCachedOwnKeys(VM& vm, JSImmutableButterfly* ownKeys)
+{
+ ensureRareData(vm)->setCachedOwnKeys(vm, ownKeys);
+}
+
+inline JSImmutableButterfly* Structure::cachedOwnKeys() const
+{
+ if (!hasRareData())
+ return nullptr;
+ return rareData()->cachedOwnKeys();
+}
+
+inline bool Structure::canCacheOwnKeys() const
+{
+ if (isDictionary())
+ return false;
+ if (hasIndexedProperties(indexingType()))
+ return false;
+ if (typeInfo().overridesGetPropertyNames())
+ return false;
+ return true;
+}
+
ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure)
{
ASSERT(!structure->isObject());
Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/StructureRareData.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -27,6 +27,7 @@
#include "StructureRareData.h"
#include "AdaptiveInferredPropertyValueWatchpointBase.h"
+#include "JSImmutableButterfly.h"
#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "JSCInlines.h"
@@ -70,18 +71,9 @@
visitor.append(thisObject->m_previous);
visitor.append(thisObject->m_objectToStringValue);
visitor.append(thisObject->m_cachedPropertyNameEnumerator);
+ visitor.append(thisObject->m_cachedOwnKeys);
}
-JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
-{
- return m_cachedPropertyNameEnumerator.get();
-}
-
-void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
-{
- m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
-}
-
// ----------- Object.prototype.toString() helper watchpoint classes -----------
class ObjectToStringAdaptiveInferredPropertyValueWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/StructureRareData.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -58,7 +58,10 @@
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
- Structure* previousID() const;
+ Structure* previousID() const
+ {
+ return m_previous.get();
+ }
void setPreviousID(VM&, Structure*);
void clearPreviousID();
@@ -68,11 +71,20 @@
JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ JSImmutableButterfly* cachedOwnKeys() const;
+ JSImmutableButterfly* cachedOwnKeysConcurrently() const;
+ void setCachedOwnKeys(VM&, JSImmutableButterfly*);
+
Box<InlineWatchpointSet> copySharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
const Box<InlineWatchpointSet>& sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; }
void setSharedPolyProtoWatchpoint(Box<InlineWatchpointSet>&& sharedPolyProtoWatchpoint) { m_polyProtoWatchpoint = WTFMove(sharedPolyProtoWatchpoint); }
bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); }
+ static ptrdiff_t offsetOfCachedOwnKeys()
+ {
+ return OBJECT_OFFSETOF(StructureRareData, m_cachedOwnKeys);
+ }
+
DECLARE_EXPORT_INFO;
private:
@@ -86,7 +98,10 @@
WriteBarrier<Structure> m_previous;
WriteBarrier<JSString> m_objectToStringValue;
+ // FIXME: We should have some story for clearing these property names caches in GC.
+ // https://bugs.webkit.org/show_bug.cgi?id=192659
WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator;
+ WriteBarrier<JSImmutableButterfly> m_cachedOwnKeys;
typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets;
Modified: trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/StructureRareDataInlines.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -25,16 +25,13 @@
#pragma once
+#include "JSImmutableButterfly.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "StructureRareData.h"
namespace JSC {
-inline Structure* StructureRareData::previousID() const
-{
- return m_previous.get();
-}
-
inline void StructureRareData::setPreviousID(VM& vm, Structure* structure)
{
m_previous.set(vm, this, structure);
@@ -50,4 +47,33 @@
return m_objectToStringValue.get();
}
+inline JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
+{
+ return m_cachedPropertyNameEnumerator.get();
+}
+
+inline void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
+}
+
+inline JSImmutableButterfly* StructureRareData::cachedOwnKeys() const
+{
+ ASSERT(!compilationOrGCThread())
+ return m_cachedOwnKeys.get();
+}
+
+inline JSImmutableButterfly* StructureRareData::cachedOwnKeysConcurrently() const
+{
+ auto* result = m_cachedOwnKeys.get();
+ WTF::loadLoadFence();
+ return result;
+}
+
+inline void StructureRareData::setCachedOwnKeys(VM& vm, JSImmutableButterfly* butterfly)
+{
+ WTF::storeStoreFence();
+ m_cachedOwnKeys.set(vm, this, butterfly);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2018-12-13 07:13:38 UTC (rev 239153)
@@ -434,6 +434,7 @@
exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull()));
+ nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull()));
moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
evalCodeBlockStructure.set(*this, EvalCodeBlock::createStructure(*this, 0, jsNull()));
@@ -447,8 +448,8 @@
sentinelSetBucket.set(*this, JSSet::BucketType::createSentinel(*this));
sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this));
+ sentinelImmutableButterfly.set(*this, JSImmutableButterfly::createSentinel(*this));
- nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
smallStrings.initializeCommonStrings(*this);
Thread::current().setCurrentAtomicStringTable(existingEntryAtomicStringTable);
Modified: trunk/Source/_javascript_Core/runtime/VM.h (239152 => 239153)
--- trunk/Source/_javascript_Core/runtime/VM.h 2018-12-13 06:51:06 UTC (rev 239152)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2018-12-13 07:13:38 UTC (rev 239153)
@@ -571,6 +571,7 @@
Strong<JSCell> emptyPropertyNameEnumerator;
Strong<JSCell> sentinelSetBucket;
Strong<JSCell> sentinelMapBucket;
+ Strong<JSCell> sentinelImmutableButterfly;
std::unique_ptr<PromiseDeferredTimer> promiseDeferredTimer;