Diff
Modified: branches/safari-612-branch/JSTests/ChangeLog (283688 => 283689)
--- branches/safari-612-branch/JSTests/ChangeLog 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/JSTests/ChangeLog 2021-10-07 00:52:56 UTC (rev 283689)
@@ -1,3 +1,106 @@
+2021-10-06 Russell Epstein <[email protected]>
+
+ Cherry-pick r283556. rdar://problem/83956477
+
+ [JSC] JSPropertyNameEnumerator should not have cached prototype chain since empty JSPropertyNameEnumerator is shared
+ https://bugs.webkit.org/show_bug.cgi?id=231202
+ JSTests:
+
+ Reviewed by Keith Miller.
+
+ * stress/for-in-validation-poly-proto.js: Added.
+ (shouldBe):
+ (test):
+ (factory.Test):
+ (factory):
+ * stress/for-in-validation-watchpoint.js: Added.
+ (shouldBe):
+ (test):
+ (Test):
+ (factory):
+
+ Source/_javascript_Core:
+
+ rdar://83815122
+
+ Reviewed by Keith Miller.
+
+ r282014 assumed an invariant that JSPropertyNameEnumerator's StructureChain is immutable.
+ This invariant is also used in validation of JSPropertyNameEnumerator. However, this
+ invariant was broken since we now have shared empty sentinel JSPropertyNameEnumerator, which can
+ be used for different structures having different prototype chain.
+
+ Since now we have shared JSPropertyNameEnumerator, JSPropertyNameEnumerator should not have
+ StructureChain in its member. When invalidating StructureChain in Structure, we also clear
+ cached JSPropertyNameEnumerator so that we do not get a stale JSPropertyNameEnumerator from
+ Structure even though watchpoint-based validation is not used.
+
+ This patch also removes ValidatedViaWatchpoint flag in JSPropertyNameEnumerator due to the same
+ reason. We should not modify JSPropertyNameEnumerator once it is instantiated. Instead, we encode
+ this flag as a lowest bit of m_cachedPropertyNameEnumerator. If it is validated via traversing (not watchpoints),
+ then this bit is set. So when loading that pointer from StructureRareData, we can quickly detect
+ it without even accessing to the enumerator. This fixes the issue, and it is even cleaner.
+ We rename m_cachedPropertyNameEnumerator to m_cachedPropertyNameEnumeratorAndFlag since it now
+ includes this flag.
+
+ While reviewing the code, we also found that watchpoint-based validation didn't care about PolyProto.
+ We should disable watchpoint-based validation if PolyProto is used.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetPropertyEnumerator):
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_property_enumerator):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/JSPropertyNameEnumerator.cpp:
+ (JSC::JSPropertyNameEnumerator::visitChildrenImpl):
+ * runtime/JSPropertyNameEnumerator.h:
+ (JSC::propertyNameEnumerator):
+ * runtime/Structure.cpp:
+ (JSC::Structure::visitChildrenImpl):
+ (JSC::Structure::setCachedPropertyNameEnumerator):
+ (JSC::Structure::cachedPropertyNameEnumeratorAndFlag const):
+ * runtime/Structure.h:
+ (JSC::Structure::propertyNameEnumeratorShouldWatch const):
+ * runtime/StructureInlines.h:
+ (JSC::Structure::prototypeChain const):
+ (JSC::Structure::clearCachedPrototypeChain):
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::visitChildrenImpl):
+ * runtime/StructureRareData.h:
+ * runtime/StructureRareDataInlines.h:
+ (JSC::StructureRareData::cachedPropertyNameEnumerator const):
+ (JSC::StructureRareData::cachedPropertyNameEnumeratorAndFlag const):
+ (JSC::StructureRareData::setCachedPropertyNameEnumerator):
+ (JSC::StructureChainInvalidationWatchpoint::fireInternal):
+ (JSC::StructureRareData::tryCachePropertyNameEnumeratorViaWatchpoint):
+ (JSC::StructureRareData::clearCachedPropertyNameEnumerator):
+ (JSC::StructureRareData::invalidateWatchpointBasedValidation): Deleted.
+
+ git-svn-id: https://svn.webkit.org/repository/webkit/trunk@283556 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+ 2021-10-05 Yusuke Suzuki <[email protected]>
+
+ [JSC] JSPropertyNameEnumerator should not have cached prototype chain since empty JSPropertyNameEnumerator is shared
+ https://bugs.webkit.org/show_bug.cgi?id=231202
+
+ Reviewed by Keith Miller.
+
+ * stress/for-in-validation-poly-proto.js: Added.
+ (shouldBe):
+ (test):
+ (factory.Test):
+ (factory):
+ * stress/for-in-validation-watchpoint.js: Added.
+ (shouldBe):
+ (test):
+ (Test):
+ (factory):
+
2021-09-27 Alan Coon <[email protected]>
Cherry-pick r283098. rdar://problem/83584491
Added: branches/safari-612-branch/JSTests/stress/for-in-validation-poly-proto.js (0 => 283689)
--- branches/safari-612-branch/JSTests/stress/for-in-validation-poly-proto.js (rev 0)
+++ branches/safari-612-branch/JSTests/stress/for-in-validation-poly-proto.js 2021-10-07 00:52:56 UTC (rev 283689)
@@ -0,0 +1,34 @@
+//@ requireOptions("--forcePolyProto=1")
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object) {
+ var result = []
+ for (var k in object)
+ result.push(k);
+ return JSON.stringify(result);
+}
+noInline(test);
+
+var constructors = []
+Object.prototype.hey = 32;
+function factory() {
+ function Test() { }
+ constructors.push(Test);
+ return new Test;
+}
+
+var object = factory();
+shouldBe(test(object), `["hey"]`);
+shouldBe(test(object), `["hey"]`);
+shouldBe(test(object), `["hey"]`);
+var object2 = factory();
+shouldBe(test(object2), `["hey"]`);
+shouldBe(test(object2), `["hey"]`);
+shouldBe(test(object2), `["hey"]`);
+object2.__proto__ = { ok: 33 };
+shouldBe(test(object2), `["ok","hey"]`);
+shouldBe(test(object2), `["ok","hey"]`);
+shouldBe(test(object2), `["ok","hey"]`);
Added: branches/safari-612-branch/JSTests/stress/for-in-validation-watchpoint.js (0 => 283689)
--- branches/safari-612-branch/JSTests/stress/for-in-validation-watchpoint.js (rev 0)
+++ branches/safari-612-branch/JSTests/stress/for-in-validation-watchpoint.js 2021-10-07 00:52:56 UTC (rev 283689)
@@ -0,0 +1,34 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function test(object) {
+ var result = []
+ for (var k in object)
+ result.push(k);
+ return JSON.stringify(result);
+}
+noInline(test);
+
+function Test() { }
+function factory() { return new Test; }
+
+var object = factory();
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+object.ok = 42;
+delete object.ok;
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+Test.prototype.ok = 42;
+delete Test.prototype.ok;
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+shouldBe(test(object), `[]`);
+Test.prototype.ok = 42;
+test({});
+test({});
+shouldBe(test(object), `["ok"]`);
Modified: branches/safari-612-branch/Source/_javascript_Core/ChangeLog (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/ChangeLog 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/ChangeLog 2021-10-07 00:52:56 UTC (rev 283689)
@@ -1,5 +1,154 @@
2021-10-06 Russell Epstein <[email protected]>
+ Cherry-pick r283556. rdar://problem/83956477
+
+ [JSC] JSPropertyNameEnumerator should not have cached prototype chain since empty JSPropertyNameEnumerator is shared
+ https://bugs.webkit.org/show_bug.cgi?id=231202
+ JSTests:
+
+ Reviewed by Keith Miller.
+
+ * stress/for-in-validation-poly-proto.js: Added.
+ (shouldBe):
+ (test):
+ (factory.Test):
+ (factory):
+ * stress/for-in-validation-watchpoint.js: Added.
+ (shouldBe):
+ (test):
+ (Test):
+ (factory):
+
+ Source/_javascript_Core:
+
+ rdar://83815122
+
+ Reviewed by Keith Miller.
+
+ r282014 assumed an invariant that JSPropertyNameEnumerator's StructureChain is immutable.
+ This invariant is also used in validation of JSPropertyNameEnumerator. However, this
+ invariant was broken since we now have shared empty sentinel JSPropertyNameEnumerator, which can
+ be used for different structures having different prototype chain.
+
+ Since now we have shared JSPropertyNameEnumerator, JSPropertyNameEnumerator should not have
+ StructureChain in its member. When invalidating StructureChain in Structure, we also clear
+ cached JSPropertyNameEnumerator so that we do not get a stale JSPropertyNameEnumerator from
+ Structure even though watchpoint-based validation is not used.
+
+ This patch also removes ValidatedViaWatchpoint flag in JSPropertyNameEnumerator due to the same
+ reason. We should not modify JSPropertyNameEnumerator once it is instantiated. Instead, we encode
+ this flag as a lowest bit of m_cachedPropertyNameEnumerator. If it is validated via traversing (not watchpoints),
+ then this bit is set. So when loading that pointer from StructureRareData, we can quickly detect
+ it without even accessing to the enumerator. This fixes the issue, and it is even cleaner.
+ We rename m_cachedPropertyNameEnumerator to m_cachedPropertyNameEnumeratorAndFlag since it now
+ includes this flag.
+
+ While reviewing the code, we also found that watchpoint-based validation didn't care about PolyProto.
+ We should disable watchpoint-based validation if PolyProto is used.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetPropertyEnumerator):
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_property_enumerator):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/JSPropertyNameEnumerator.cpp:
+ (JSC::JSPropertyNameEnumerator::visitChildrenImpl):
+ * runtime/JSPropertyNameEnumerator.h:
+ (JSC::propertyNameEnumerator):
+ * runtime/Structure.cpp:
+ (JSC::Structure::visitChildrenImpl):
+ (JSC::Structure::setCachedPropertyNameEnumerator):
+ (JSC::Structure::cachedPropertyNameEnumeratorAndFlag const):
+ * runtime/Structure.h:
+ (JSC::Structure::propertyNameEnumeratorShouldWatch const):
+ * runtime/StructureInlines.h:
+ (JSC::Structure::prototypeChain const):
+ (JSC::Structure::clearCachedPrototypeChain):
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::visitChildrenImpl):
+ * runtime/StructureRareData.h:
+ * runtime/StructureRareDataInlines.h:
+ (JSC::StructureRareData::cachedPropertyNameEnumerator const):
+ (JSC::StructureRareData::cachedPropertyNameEnumeratorAndFlag const):
+ (JSC::StructureRareData::setCachedPropertyNameEnumerator):
+ (JSC::StructureChainInvalidationWatchpoint::fireInternal):
+ (JSC::StructureRareData::tryCachePropertyNameEnumeratorViaWatchpoint):
+ (JSC::StructureRareData::clearCachedPropertyNameEnumerator):
+ (JSC::StructureRareData::invalidateWatchpointBasedValidation): Deleted.
+
+ git-svn-id: https://svn.webkit.org/repository/webkit/trunk@283556 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+ 2021-10-05 Yusuke Suzuki <[email protected]>
+
+ [JSC] JSPropertyNameEnumerator should not have cached prototype chain since empty JSPropertyNameEnumerator is shared
+ https://bugs.webkit.org/show_bug.cgi?id=231202
+ rdar://83815122
+
+ Reviewed by Keith Miller.
+
+ r282014 assumed an invariant that JSPropertyNameEnumerator's StructureChain is immutable.
+ This invariant is also used in validation of JSPropertyNameEnumerator. However, this
+ invariant was broken since we now have shared empty sentinel JSPropertyNameEnumerator, which can
+ be used for different structures having different prototype chain.
+
+ Since now we have shared JSPropertyNameEnumerator, JSPropertyNameEnumerator should not have
+ StructureChain in its member. When invalidating StructureChain in Structure, we also clear
+ cached JSPropertyNameEnumerator so that we do not get a stale JSPropertyNameEnumerator from
+ Structure even though watchpoint-based validation is not used.
+
+ This patch also removes ValidatedViaWatchpoint flag in JSPropertyNameEnumerator due to the same
+ reason. We should not modify JSPropertyNameEnumerator once it is instantiated. Instead, we encode
+ this flag as a lowest bit of m_cachedPropertyNameEnumerator. If it is validated via traversing (not watchpoints),
+ then this bit is set. So when loading that pointer from StructureRareData, we can quickly detect
+ it without even accessing to the enumerator. This fixes the issue, and it is even cleaner.
+ We rename m_cachedPropertyNameEnumerator to m_cachedPropertyNameEnumeratorAndFlag since it now
+ includes this flag.
+
+ While reviewing the code, we also found that watchpoint-based validation didn't care about PolyProto.
+ We should disable watchpoint-based validation if PolyProto is used.
+
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetPropertyEnumerator):
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_property_enumerator):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/JSPropertyNameEnumerator.cpp:
+ (JSC::JSPropertyNameEnumerator::visitChildrenImpl):
+ * runtime/JSPropertyNameEnumerator.h:
+ (JSC::propertyNameEnumerator):
+ * runtime/Structure.cpp:
+ (JSC::Structure::visitChildrenImpl):
+ (JSC::Structure::setCachedPropertyNameEnumerator):
+ (JSC::Structure::cachedPropertyNameEnumeratorAndFlag const):
+ * runtime/Structure.h:
+ (JSC::Structure::propertyNameEnumeratorShouldWatch const):
+ * runtime/StructureInlines.h:
+ (JSC::Structure::prototypeChain const):
+ (JSC::Structure::clearCachedPrototypeChain):
+ * runtime/StructureRareData.cpp:
+ (JSC::StructureRareData::visitChildrenImpl):
+ * runtime/StructureRareData.h:
+ * runtime/StructureRareDataInlines.h:
+ (JSC::StructureRareData::cachedPropertyNameEnumerator const):
+ (JSC::StructureRareData::cachedPropertyNameEnumeratorAndFlag const):
+ (JSC::StructureRareData::setCachedPropertyNameEnumerator):
+ (JSC::StructureChainInvalidationWatchpoint::fireInternal):
+ (JSC::StructureRareData::tryCachePropertyNameEnumeratorViaWatchpoint):
+ (JSC::StructureRareData::clearCachedPropertyNameEnumerator):
+ (JSC::StructureRareData::invalidateWatchpointBasedValidation): Deleted.
+
+2021-10-06 Russell Epstein <[email protected]>
+
Cherry-pick r283444. rdar://problem/83960033
Remove JSC hack after r283410
Modified: branches/safari-612-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -13995,7 +13995,7 @@
if (rareData) {
FrozenValue* frozenRareData = m_graph.freeze(rareData);
m_jit.move(TrustedImmPtr(frozenRareData), scratch1GPR);
- m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumerator()), scratch1GPR);
+ m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumeratorAndFlag()), scratch1GPR);
} else {
if (onlyStructure)
m_jit.move(TrustedImmPtr(onlyStructure), scratch1GPR);
@@ -14004,11 +14004,11 @@
m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, Structure::previousOrRareDataOffset()), scratch1GPR);
slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratch1GPR));
slowCases.append(m_jit.branchIfStructure(scratch1GPR));
- m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumerator()), scratch1GPR);
+ m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumeratorAndFlag()), scratch1GPR);
}
slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratch1GPR));
- slowCases.append(m_jit.branchTest32(CCallHelpers::Zero, CCallHelpers::Address(scratch1GPR, JSPropertyNameEnumerator::flagsOffset()), CCallHelpers::TrustedImm32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)));
+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::NonZero, scratch1GPR, CCallHelpers::TrustedImm32(StructureRareData::cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag)));
doneCases.append(m_jit.jump());
slowCases.link(&m_jit);
Modified: branches/safari-612-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -110,7 +110,6 @@
macro(JSObject_butterfly, JSObject::butterflyOffset()) \
macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \
macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \
- macro(JSPropertyNameEnumerator_cachedPrototypeChain, JSPropertyNameEnumerator::offsetOfCachedPrototypeChain()) \
macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \
macro(JSPropertyNameEnumerator_endGenericPropertyIndex, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()) \
macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \
@@ -153,7 +152,7 @@
macro(Structure_structureID, Structure::structureIDOffset()) \
macro(StructureRareData_cachedKeys, StructureRareData::offsetOfCachedPropertyNames(CachedPropertyNamesKind::Keys)) \
macro(StructureRareData_cachedGetOwnPropertyNames, StructureRareData::offsetOfCachedPropertyNames(CachedPropertyNamesKind::GetOwnPropertyNames)) \
- macro(StructureRareData_cachedPropertyNameEnumerator, StructureRareData::offsetOfCachedPropertyNameEnumerator()) \
+ macro(StructureRareData_cachedPropertyNameEnumeratorAndFlag, StructureRareData::offsetOfCachedPropertyNameEnumeratorAndFlag()) \
macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \
macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \
macro(HashMapImpl_head, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()) \
Modified: branches/safari-612-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -13300,12 +13300,12 @@
m_out.branch(isRareData, unsure(rareDataCase), unsure(genericCase));
m_out.appendTo(rareDataCase, validationCase);
- LValue cached = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedPropertyNameEnumerator);
- m_out.branch(m_out.notNull(cached), unsure(validationCase), unsure(genericCase));
+ LValue cachedAndFlag = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedPropertyNameEnumeratorAndFlag);
+ m_out.branch(m_out.notNull(cachedAndFlag), unsure(validationCase), unsure(genericCase));
m_out.appendTo(validationCase, genericCase);
- results.append(m_out.anchor(cached));
- m_out.branch(m_out.testNonZero32(m_out.load32(cached, m_heaps.JSPropertyNameEnumerator_flags), m_out.constInt32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)), unsure(continuation), unsure(genericCase));
+ results.append(m_out.anchor(cachedAndFlag));
+ m_out.branch(m_out.testIsZeroPtr(cachedAndFlag, m_out.constIntPtr(StructureRareData::cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag)), unsure(continuation), unsure(genericCase));
m_out.appendTo(genericCase, continuation);
results.append(m_out.anchor(vmCall(pointerType(), operationGetPropertyEnumeratorCell, weakPointer(globalObject), base)));
Modified: branches/safari-612-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -2806,10 +2806,10 @@
loadPtr(Address(regT1, Structure::previousOrRareDataOffset()), regT1);
genericCases.append(branchTestPtr(Zero, regT1));
genericCases.append(branchIfStructure(regT1));
- loadPtr(Address(regT1, StructureRareData::offsetOfCachedPropertyNameEnumerator()), regT1);
+ loadPtr(Address(regT1, StructureRareData::offsetOfCachedPropertyNameEnumeratorAndFlag()), regT1);
genericCases.append(branchTestPtr(Zero, regT1));
- genericCases.append(branchTest32(Zero, Address(regT1, JSPropertyNameEnumerator::flagsOffset()), TrustedImm32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)));
+ genericCases.append(branchTestPtr(NonZero, regT1, TrustedImm32(StructureRareData::cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag)));
emitPutVirtualRegister(dst, regT1);
doneCases.append(jump());
Modified: branches/safari-612-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -962,7 +962,7 @@
metadata.m_offset = slot.cachedOffset();
metadata.m_newStructureID = newStructure->id();
if (!(bytecode.m_flags.isDirect())) {
- StructureChain* chain = newStructure->prototypeChain(globalObject, asObject(baseCell));
+ StructureChain* chain = newStructure->prototypeChain(vm, globalObject, asObject(baseCell));
ASSERT(chain);
metadata.m_structureChain.set(vm, codeBlock, chain);
}
Modified: branches/safari-612-branch/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-10-07 00:52:56 UTC (rev 283689)
@@ -3119,9 +3119,9 @@
btpz t1, .slowPath
bbeq JSCell::m_type[t1], StructureType, .slowPath
- loadp StructureRareData::m_cachedPropertyNameEnumerator[t1], t1
+ loadp StructureRareData::m_cachedPropertyNameEnumeratorAndFlag[t1], t1
btpz t1, .slowPath
- btiz JSPropertyNameEnumerator::m_flags[t1], (constexpr JSPropertyNameEnumerator::ValidatedViaWatchpoint), .slowPath
+ btpnz t1, (constexpr StructureRareData::cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag), .slowPath
return(t1)
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -86,7 +86,6 @@
visitor.markAuxiliary(propertyNames);
visitor.append(propertyNames, propertyNames + thisObject->sizeOfPropertyNames());
}
- visitor.append(thisObject->m_prototypeChain);
if (thisObject->cachedStructureID()) {
VM& vm = visitor.vm();
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -44,8 +44,6 @@
GenericMode = 1 << 2,
// Profiling Only
HasSeenOwnStructureModeStructureMismatch = 1 << 3,
- // JSPropertyNameEnumerator Only
- ValidatedViaWatchpoint = 1 << 4,
};
static constexpr uint8_t enumerationModeMask = (GenericMode << 1) - 1;
@@ -72,10 +70,6 @@
return m_propertyNames.get()[index].get();
}
- StructureChain* cachedPrototypeChain() const { return m_prototypeChain.get(); }
- void setCachedPrototypeChain(VM& vm, StructureChain* prototypeChain) { return m_prototypeChain.set(vm, this, prototypeChain); }
- static ptrdiff_t offsetOfCachedPrototypeChain() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_prototypeChain); }
-
Structure* cachedStructure(VM& vm) const
{
if (!m_cachedStructureID)
@@ -100,15 +94,6 @@
return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames);
}
- bool validatedViaWatchpoint() const { return m_flags & JSPropertyNameEnumerator::ValidatedViaWatchpoint; }
- void setValidatedViaWatchpoint(bool validatedViaWatchpoint)
- {
- if (validatedViaWatchpoint)
- m_flags |= JSPropertyNameEnumerator::ValidatedViaWatchpoint;
- else
- m_flags &= ~JSPropertyNameEnumerator::ValidatedViaWatchpoint;
- }
-
JSString* computeNext(JSGlobalObject*, JSObject* base, uint32_t& currentIndex, Flag&, bool shouldAllocateIndexedNameString = true);
DECLARE_VISIT_CHILDREN;
@@ -119,8 +104,9 @@
JSPropertyNameEnumerator(VM&, Structure*, uint32_t, uint32_t, WriteBarrier<JSString>*, unsigned);
void finishCreation(VM&, RefPtr<PropertyNameArrayData>&&);
+ // JSPropertyNameEnumerator is immutable data structure, which allows VM to cache the empty one.
+ // After instantiating JSPropertyNameEnumerator, we must not change any fields.
AuxiliaryBarrier<WriteBarrier<JSString>*> m_propertyNames;
- WriteBarrier<StructureChain> m_prototypeChain;
StructureID m_cachedStructureID;
uint32_t m_indexedLength;
uint32_t m_endStructurePropertyIndex;
@@ -138,13 +124,16 @@
uint32_t indexedLength = base->getEnumerableLength(globalObject);
- JSPropertyNameEnumerator* enumerator = nullptr;
-
Structure* structure = base->structure(vm);
- if (!indexedLength
- && (enumerator = structure->cachedPropertyNameEnumerator())) {
- if (enumerator->validatedViaWatchpoint() || enumerator->cachedPrototypeChain() == structure->prototypeChain(globalObject, base))
- return enumerator;
+ if (!indexedLength) {
+ uintptr_t enumeratorAndFlag = structure->cachedPropertyNameEnumeratorAndFlag();
+ if (enumeratorAndFlag) {
+ if (!(enumeratorAndFlag & StructureRareData::cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag))
+ return bitwise_cast<JSPropertyNameEnumerator*>(enumeratorAndFlag);
+ structure->prototypeChain(vm, globalObject, base); // Refresh cached structure chain.
+ if (auto* enumerator = structure->cachedPropertyNameEnumerator())
+ return enumerator;
+ }
}
uint32_t numberStructureProperties = 0;
@@ -163,14 +152,15 @@
numberStructureProperties = 0;
}
+ JSPropertyNameEnumerator* enumerator = nullptr;
if (!indexedLength && !propertyNames.size())
enumerator = vm.emptyPropertyNameEnumerator();
else
enumerator = JSPropertyNameEnumerator::create(vm, structureAfterGettingPropertyNames, indexedLength, numberStructureProperties, WTFMove(propertyNames));
if (!indexedLength && successfullyNormalizedChain && structureAfterGettingPropertyNames == structure) {
- enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(globalObject, base));
+ StructureChain* chain = structure->prototypeChain(vm, globalObject, base);
if (structure->canCachePropertyNameEnumerator(vm))
- structure->setCachedPropertyNameEnumerator(vm, enumerator);
+ structure->setCachedPropertyNameEnumerator(vm, enumerator, chain);
}
return enumerator;
}
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -1229,9 +1229,15 @@
ConcurrentJSLocker locker(thisObject->m_lock);
visitor.append(thisObject->m_globalObject);
- if (!thisObject->isObject())
+ if (!thisObject->isObject()) {
+ // We do not need to clear JSPropertyNameEnumerator since it is never cached for non-object Structure.
+ // We do not have code clearing JSPropertyNameEnumerator since this function can be called concurrently.
thisObject->m_cachedPrototypeChain.clear();
- else {
+#if ASSERT_ENABLED
+ if (auto* rareData = thisObject->tryRareData())
+ ASSERT(!rareData->cachedPropertyNameEnumerator());
+#endif
+ } else {
visitor.append(thisObject->m_prototype);
visitor.append(thisObject->m_cachedPrototypeChain);
}
@@ -1394,12 +1400,14 @@
return false;
}
-void Structure::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+void Structure::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator, StructureChain* chain)
{
+ ASSERT(typeInfo().isObject());
ASSERT(!isDictionary());
if (!hasRareData())
allocateRareData(vm);
- rareData()->setCachedPropertyNameEnumerator(vm, enumerator);
+ ASSERT(chain == m_cachedPrototypeChain.get());
+ rareData()->setCachedPropertyNameEnumerator(vm, this, enumerator, chain);
}
JSPropertyNameEnumerator* Structure::cachedPropertyNameEnumerator() const
@@ -1409,6 +1417,13 @@
return rareData()->cachedPropertyNameEnumerator();
}
+uintptr_t Structure::cachedPropertyNameEnumeratorAndFlag() const
+{
+ if (!hasRareData())
+ return 0;
+ return rareData()->cachedPropertyNameEnumeratorAndFlag();
+}
+
bool Structure::canCachePropertyNameEnumerator(VM& vm) const
{
if (!this->canCacheOwnPropertyNames())
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/Structure.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -307,7 +307,6 @@
JSValue prototypeForLookup(JSGlobalObject*) const;
JSValue prototypeForLookup(JSGlobalObject*, JSCell* base) const;
StructureChain* prototypeChain(VM&, JSGlobalObject*, JSObject* base) const;
- StructureChain* prototypeChain(JSGlobalObject*, JSObject* base) const;
DECLARE_VISIT_CHILDREN;
// A Structure is cheap to mark during GC if doing so would only add a small and bounded amount
@@ -530,8 +529,9 @@
setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
}
- void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*, StructureChain*);
JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+ uintptr_t cachedPropertyNameEnumeratorAndFlag() const;
bool canCachePropertyNameEnumerator(VM&) const;
bool canAccessPropertiesQuicklyForEnumeration() const;
@@ -637,7 +637,7 @@
bool propertyNameEnumeratorShouldWatch() const
{
- return dfgShouldWatch();
+ return dfgShouldWatch() && !hasPolyProto();
}
void addTransitionWatchpoint(Watchpoint* watchpoint) const
@@ -849,6 +849,8 @@
void startWatchingInternalProperties(VM&);
+ void clearCachedPrototypeChain();
+
static constexpr int s_maxTransitionLength = 64;
static constexpr int s_maxTransitionLengthForNonEvalPutById = 512;
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/StructureInlines.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/StructureInlines.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/StructureInlines.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -342,16 +342,12 @@
// We cache our prototype chain so our clients can share it.
if (!isValid(globalObject, m_cachedPrototypeChain.get(), base)) {
JSValue prototype = prototypeForLookup(globalObject, base);
+ const_cast<Structure*>(this)->clearCachedPrototypeChain();
m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? nullptr : asObject(prototype)));
}
return m_cachedPrototypeChain.get();
}
-inline StructureChain* Structure::prototypeChain(JSGlobalObject* globalObject, JSObject* base) const
-{
- return prototypeChain(globalObject->vm(), globalObject, base);
-}
-
inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain, JSObject* base) const
{
if (!cachedPrototypeChain)
@@ -759,4 +755,12 @@
return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, transitionKind));
}
+inline void Structure::clearCachedPrototypeChain()
+{
+ m_cachedPrototypeChain.clear();
+ if (!hasRareData())
+ return;
+ rareData()->clearCachedPropertyNameEnumerator();
+}
+
} // namespace JSC
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.cpp (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.cpp 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.cpp 2021-10-07 00:52:56 UTC (rev 283689)
@@ -79,7 +79,7 @@
for (unsigned index = 0; index < numberOfCachedSpecialPropertyKeys; ++index)
visitor.appendUnbarriered(thisObject->cachedSpecialProperty(static_cast<CachedSpecialPropertyKey>(index)));
}
- visitor.append(thisObject->m_cachedPropertyNameEnumerator);
+ visitor.appendUnbarriered(thisObject->cachedPropertyNameEnumerator());
for (unsigned index = 0; index < numberOfCachedPropertyNames; ++index) {
auto* cached = thisObject->m_cachedPropertyNames[index].unvalidatedGet();
if (cached != cachedPropertyNamesSentinel())
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareData.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -89,7 +89,9 @@
void cacheSpecialProperty(JSGlobalObject*, VM&, Structure* baseStructure, JSValue, CachedSpecialPropertyKey, const PropertySlot&);
JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
- void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ uintptr_t cachedPropertyNameEnumeratorAndFlag() const;
+ void setCachedPropertyNameEnumerator(VM&, Structure*, JSPropertyNameEnumerator*, StructureChain*);
+ void clearCachedPropertyNameEnumerator();
JSImmutableButterfly* cachedPropertyNames(CachedPropertyNamesKind) const;
JSImmutableButterfly* cachedPropertyNamesIgnoringSentinel(CachedPropertyNamesKind) const;
@@ -108,9 +110,9 @@
return OBJECT_OFFSETOF(StructureRareData, m_cachedPropertyNames) + sizeof(WriteBarrier<JSImmutableButterfly>) * static_cast<unsigned>(kind);
}
- static ptrdiff_t offsetOfCachedPropertyNameEnumerator()
+ static ptrdiff_t offsetOfCachedPropertyNameEnumeratorAndFlag()
{
- return OBJECT_OFFSETOF(StructureRareData, m_cachedPropertyNameEnumerator);
+ return OBJECT_OFFSETOF(StructureRareData, m_cachedPropertyNameEnumeratorAndFlag);
}
DECLARE_EXPORT_INFO;
@@ -117,7 +119,8 @@
void finalizeUnconditionally(VM&);
- void invalidateWatchpointBasedValidation();
+ static constexpr uintptr_t cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag = 1;
+ static constexpr uintptr_t cachedPropertyNameEnumeratorMask = ~static_cast<uintptr_t>(1);
private:
friend class LLIntOffsetsExtractor;
@@ -135,12 +138,12 @@
bool canCacheSpecialProperty(CachedSpecialPropertyKey);
void giveUpOnSpecialPropertyCache(CachedSpecialPropertyKey);
- bool tryCachePropertyNameEnumeratorViaWatchpoint(VM&, StructureChain*);
+ bool tryCachePropertyNameEnumeratorViaWatchpoint(VM&, Structure*, StructureChain*);
WriteBarrier<Structure> m_previous;
// 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;
+ uintptr_t m_cachedPropertyNameEnumeratorAndFlag { 0 };
FixedVector<StructureChainInvalidationWatchpoint> m_cachedPropertyNameEnumeratorWatchpoints;
WriteBarrier<JSImmutableButterfly> m_cachedPropertyNames[numberOfCachedPropertyNames] { };
Modified: branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareDataInlines.h (283688 => 283689)
--- branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareDataInlines.h 2021-10-07 00:52:50 UTC (rev 283688)
+++ branches/safari-612-branch/Source/_javascript_Core/runtime/StructureRareDataInlines.h 2021-10-07 00:52:56 UTC (rev 283689)
@@ -90,15 +90,20 @@
inline JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
{
- return m_cachedPropertyNameEnumerator.get();
+ return bitwise_cast<JSPropertyNameEnumerator*>(m_cachedPropertyNameEnumeratorAndFlag & cachedPropertyNameEnumeratorMask);
}
-inline void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+inline uintptr_t StructureRareData::cachedPropertyNameEnumeratorAndFlag() const
{
- m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
+ return m_cachedPropertyNameEnumeratorAndFlag;
+}
+
+inline void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, Structure* baseStructure, JSPropertyNameEnumerator* enumerator, StructureChain* chain)
+{
m_cachedPropertyNameEnumeratorWatchpoints = FixedVector<StructureChainInvalidationWatchpoint>();
- bool validatedViaWatchpoint = tryCachePropertyNameEnumeratorViaWatchpoint(vm, enumerator->cachedPrototypeChain());
- enumerator->setValidatedViaWatchpoint(validatedViaWatchpoint);
+ bool validatedViaWatchpoint = tryCachePropertyNameEnumeratorViaWatchpoint(vm, baseStructure, chain);
+ m_cachedPropertyNameEnumeratorAndFlag = ((validatedViaWatchpoint ? 0 : cachedPropertyNameEnumeratorIsValidatedViaTraversingFlag) | bitwise_cast<uintptr_t>(enumerator));
+ vm.heap.writeBarrier(this, enumerator);
}
inline JSImmutableButterfly* StructureRareData::cachedPropertyNames(CachedPropertyNamesKind kind) const
@@ -169,11 +174,14 @@
{
if (!m_structureRareData->isLive())
return;
- m_structureRareData->invalidateWatchpointBasedValidation();
+ m_structureRareData->clearCachedPropertyNameEnumerator();
}
-inline bool StructureRareData::tryCachePropertyNameEnumeratorViaWatchpoint(VM& vm, StructureChain* chain)
+inline bool StructureRareData::tryCachePropertyNameEnumeratorViaWatchpoint(VM& vm, Structure* baseStructure, StructureChain* chain)
{
+ if (baseStructure->hasPolyProto())
+ return false;
+
unsigned size = 0;
for (auto* current = chain->head(); *current; ++current) {
++size;
@@ -193,9 +201,9 @@
return true;
}
-inline void StructureRareData::invalidateWatchpointBasedValidation()
+inline void StructureRareData::clearCachedPropertyNameEnumerator()
{
- m_cachedPropertyNameEnumerator.clear();
+ m_cachedPropertyNameEnumeratorAndFlag = 0;
m_cachedPropertyNameEnumeratorWatchpoints = FixedVector<StructureChainInvalidationWatchpoint>();
}