Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (265639 => 265640)
--- trunk/Source/_javascript_Core/ChangeLog 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-08-14 01:56:43 UTC (rev 265640)
@@ -1,3 +1,71 @@
+2020-08-13 Alexey Shvayka <[email protected]>
+
+ Rework StructureTransitionTable::Hash::Key encoding
+ https://bugs.webkit.org/show_bug.cgi?id=215483
+
+ Reviewed by Yusuke Suzuki.
+
+ This patch implements new encoding of StructureTransitionTable::Hash::Key
+ to enable storing attribute change transitions in a transition table.
+
+ Since PropertyMapEntry attributes are always uint8_t, the remaining 8 bits
+ are used for TransitionKind, which also accommodates non-property transitions,
+ removing a bit hacky toAttributes() and utilization of unused pointer bits.
+
+ This change also introduces TransitionKind::Unknown we can validate against,
+ preventing addition transition from being a default, which could be unsafe.
+
+ No behavior change.
+
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::notifyPresenceOfIndexedAccessors):
+ (JSC::JSObject::createInitialUndecided):
+ (JSC::JSObject::createInitialInt32):
+ (JSC::JSObject::createInitialDouble):
+ (JSC::JSObject::createInitialContiguous):
+ (JSC::JSObject::convertUndecidedToInt32):
+ (JSC::JSObject::convertUndecidedToDouble):
+ (JSC::JSObject::convertUndecidedToContiguous):
+ (JSC::JSObject::convertUndecidedToArrayStorage):
+ (JSC::JSObject::convertInt32ToDouble):
+ (JSC::JSObject::convertInt32ToContiguous):
+ (JSC::JSObject::convertInt32ToArrayStorage):
+ (JSC::JSObject::convertDoubleToContiguous):
+ (JSC::JSObject::convertDoubleToArrayStorage):
+ (JSC::JSObject::convertContiguousToArrayStorage):
+ (JSC::JSObject::convertFromCopyOnWrite):
+ (JSC::JSObject::switchToSlowPutArrayStorage):
+ (JSC::JSObject::suggestedArrayStorageTransition const):
+ * runtime/JSObject.h:
+ * runtime/Structure.cpp:
+ (JSC::StructureTransitionTable::contains const):
+ (JSC::StructureTransitionTable::get const):
+ (JSC::StructureTransitionTable::add):
+ (JSC::Structure::Structure):
+ (JSC::Structure::addPropertyTransitionToExistingStructureImpl):
+ (JSC::Structure::addNewPropertyTransition):
+ (JSC::Structure::removePropertyTransitionFromExistingStructureImpl):
+ (JSC::Structure::removeNewPropertyTransition):
+ (JSC::Structure::sealTransition):
+ (JSC::Structure::freezeTransition):
+ (JSC::Structure::preventExtensionsTransition):
+ (JSC::Structure::nonPropertyTransitionSlow):
+ * runtime/Structure.h:
+ * runtime/StructureInlines.h:
+ (JSC::Structure::nonPropertyTransition):
+ * runtime/StructureTransitionTable.h:
+ (JSC::changesIndexingType):
+ (JSC::newIndexingType):
+ (JSC::preventsExtensions):
+ (JSC::setsDontDeleteOnAllProperties):
+ (JSC::setsReadOnlyOnNonAccessorProperties):
+ (JSC::StructureTransitionTable::Hash::Key::Key):
+ (JSC::StructureTransitionTable::Hash::Key::attributes const):
+ (JSC::StructureTransitionTable::Hash::Key::transitionKind const):
+ (JSC::StructureTransitionTable::Hash::hash):
+ (JSC::toAttributes): Deleted.
+ (JSC::StructureTransitionTable::Hash::Key::isAddition const): Deleted.
+
2020-08-12 Keith Rollin <[email protected]>
Remove the need for defining USE_NEW_BUILD_SYSTEM
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2020-08-14 01:56:43 UTC (rev 265640)
@@ -1078,7 +1078,7 @@
if (mayInterceptIndexedAccesses(vm))
return;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AddIndexedAccessors));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AddIndexedAccessors));
if (!mayBePrototype())
return;
@@ -1110,7 +1110,7 @@
Butterfly* newButterfly = createInitialIndexedStorage(vm, length);
StructureID oldStructureID = this->structureID();
Structure* oldStructure = vm.getStructure(oldStructureID);
- Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateUndecided);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, TransitionKind::AllocateUndecided);
nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
setStructure(vm, newStructure);
return newButterfly;
@@ -1124,7 +1124,7 @@
newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
StructureID oldStructureID = this->structureID();
Structure* oldStructure = vm.getStructure(oldStructureID);
- Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateInt32);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, TransitionKind::AllocateInt32);
nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
setStructure(vm, newStructure);
return newButterfly->contiguousInt32();
@@ -1138,7 +1138,7 @@
newButterfly->contiguousDouble().at(this, i) = PNaN;
StructureID oldStructureID = this->structureID();
Structure* oldStructure = vm.getStructure(oldStructureID);
- Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateDouble);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, TransitionKind::AllocateDouble);
nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
setStructure(vm, newStructure);
return newButterfly->contiguousDouble();
@@ -1152,7 +1152,7 @@
newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
StructureID oldStructureID = this->structureID();
Structure* oldStructure = vm.getStructure(oldStructureID);
- Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateContiguous);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, TransitionKind::AllocateContiguous);
nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
setStructure(vm, newStructure);
return newButterfly->contiguous();
@@ -1207,7 +1207,7 @@
for (unsigned i = butterfly->vectorLength(); i--;)
butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateInt32));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateInt32));
return m_butterfly->contiguousInt32();
}
@@ -1219,7 +1219,7 @@
for (unsigned i = butterfly->vectorLength(); i--;)
butterfly->contiguousDouble().at(this, i) = PNaN;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateDouble));
return m_butterfly->contiguousDouble();
}
@@ -1232,7 +1232,7 @@
butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue());
WTF::storeStoreFence();
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateContiguous));
return m_butterfly->contiguous();
}
@@ -1259,7 +1259,7 @@
return newStorage;
}
-ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, TransitionKind transition)
{
DeferGC deferGC(vm.heap);
ASSERT(hasUndecided(indexingType()));
@@ -1302,7 +1302,7 @@
*currentAsDouble = v.asInt32();
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateDouble));
return m_butterfly->contiguousDouble();
}
@@ -1310,11 +1310,11 @@
{
ASSERT(hasInt32(indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateContiguous));
return m_butterfly->contiguous();
}
-ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
+ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, TransitionKind transition)
{
DeferGC deferGC(vm.heap);
ASSERT(hasInt32(indexingType()));
@@ -1361,11 +1361,11 @@
}
WTF::storeStoreFence();
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::AllocateContiguous));
return m_butterfly->contiguous();
}
-ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
+ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, TransitionKind transition)
{
DeferGC deferGC(vm.heap);
ASSERT(hasDouble(indexingType()));
@@ -1396,7 +1396,7 @@
return convertDoubleToArrayStorage(vm, suggestedArrayStorageTransition(vm));
}
-ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
+ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, TransitionKind transition)
{
DeferGC deferGC(vm.heap);
ASSERT(hasContiguous(indexingType()));
@@ -1540,17 +1540,17 @@
gcSafeMemcpy(newButterfly->propertyStorage(), oldButterfly->propertyStorage(), oldButterfly->vectorLength() * sizeof(JSValue) + sizeof(IndexingHeader));
WTF::storeStoreFence();
- NonPropertyTransition transition = ([&] () {
+ TransitionKind transition = ([&] () {
switch (indexingType()) {
case ArrayWithInt32:
- return NonPropertyTransition::AllocateInt32;
+ return TransitionKind::AllocateInt32;
case ArrayWithDouble:
- return NonPropertyTransition::AllocateDouble;
+ return TransitionKind::AllocateDouble;
case ArrayWithContiguous:
- return NonPropertyTransition::AllocateContiguous;
+ return TransitionKind::AllocateContiguous;
default:
RELEASE_ASSERT_NOT_REACHED();
- return NonPropertyTransition::AllocateContiguous;
+ return TransitionKind::AllocateContiguous;
}
})();
StructureID oldStructureID = structureID();
@@ -1785,24 +1785,24 @@
break;
case ALL_UNDECIDED_INDEXING_TYPES:
- convertUndecidedToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
+ convertUndecidedToArrayStorage(vm, TransitionKind::AllocateSlowPutArrayStorage);
break;
case ALL_INT32_INDEXING_TYPES:
- convertInt32ToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
+ convertInt32ToArrayStorage(vm, TransitionKind::AllocateSlowPutArrayStorage);
break;
case ALL_DOUBLE_INDEXING_TYPES:
- convertDoubleToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
+ convertDoubleToArrayStorage(vm, TransitionKind::AllocateSlowPutArrayStorage);
break;
case ALL_CONTIGUOUS_INDEXING_TYPES:
- convertContiguousToArrayStorage(vm, NonPropertyTransition::AllocateSlowPutArrayStorage);
+ convertContiguousToArrayStorage(vm, TransitionKind::AllocateSlowPutArrayStorage);
break;
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::SwitchToSlowPutArrayStorage);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), TransitionKind::SwitchToSlowPutArrayStorage);
setStructure(vm, newStructure);
break;
}
@@ -3904,12 +3904,12 @@
return anyObjectInChainMayInterceptIndexedAccesses(vm) || globalObject(vm)->isHavingABadTime();
}
-NonPropertyTransition JSObject::suggestedArrayStorageTransition(VM& vm) const
+TransitionKind JSObject::suggestedArrayStorageTransition(VM& vm) const
{
if (needsSlowPutIndexing(vm))
- return NonPropertyTransition::AllocateSlowPutArrayStorage;
+ return TransitionKind::AllocateSlowPutArrayStorage;
- return NonPropertyTransition::AllocateArrayStorage;
+ return TransitionKind::AllocateArrayStorage;
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2020-08-14 01:56:43 UTC (rev 265640)
@@ -84,12 +84,6 @@
extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeEnumerabilityError;
extern JS_EXPORT_PRIVATE const ASCIILiteral UnconfigurablePropertyChangeWritabilityError;
-COMPILE_ASSERT(PropertyAttribute::None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
-COMPILE_ASSERT(PropertyAttribute::ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
-COMPILE_ASSERT(PropertyAttribute::DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
-COMPILE_ASSERT(PropertyAttribute::DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
-COMPILE_ASSERT(PropertyAttribute::Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
-
class JSFinalObject;
#if ASSERT_ENABLED
@@ -824,7 +818,7 @@
bool needsSlowPutIndexing(VM&) const;
private:
- NonPropertyTransition suggestedArrayStorageTransition(VM&) const;
+ TransitionKind suggestedArrayStorageTransition(VM&) const;
public:
// You should only call isStructureExtensible() when:
// - Performing this check in a way that isn't described in the specification
@@ -1032,19 +1026,19 @@
ContiguousJSValues convertUndecidedToInt32(VM&);
ContiguousDoubles convertUndecidedToDouble(VM&);
ContiguousJSValues convertUndecidedToContiguous(VM&);
- ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
+ ArrayStorage* convertUndecidedToArrayStorage(VM&, TransitionKind);
ArrayStorage* convertUndecidedToArrayStorage(VM&);
ContiguousDoubles convertInt32ToDouble(VM&);
ContiguousJSValues convertInt32ToContiguous(VM&);
- ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
+ ArrayStorage* convertInt32ToArrayStorage(VM&, TransitionKind);
ArrayStorage* convertInt32ToArrayStorage(VM&);
ContiguousJSValues convertDoubleToContiguous(VM&);
- ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
+ ArrayStorage* convertDoubleToArrayStorage(VM&, TransitionKind);
ArrayStorage* convertDoubleToArrayStorage(VM&);
- ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
+ ArrayStorage* convertContiguousToArrayStorage(VM&, TransitionKind);
ArrayStorage* convertContiguousToArrayStorage(VM&);
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2020-08-14 01:56:43 UTC (rev 265640)
@@ -78,22 +78,22 @@
m_data = bitwise_cast<intptr_t>(impl) | UsingSingleSlotFlag;
}
-bool StructureTransitionTable::contains(UniquedStringImpl* rep, unsigned attributes, bool isAddition) const
+bool StructureTransitionTable::contains(UniquedStringImpl* rep, unsigned attributes, TransitionKind transitionKind) const
{
if (isUsingSingleSlot()) {
Structure* transition = singleTransition();
- return transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->isPropertyDeletionTransition() == !isAddition;
+ return transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->transitionKind() == transitionKind;
}
- return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, isAddition));
+ return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, transitionKind));
}
-inline Structure* StructureTransitionTable::get(UniquedStringImpl* rep, unsigned attributes, bool isAddition) const
+inline Structure* StructureTransitionTable::get(UniquedStringImpl* rep, unsigned attributes, TransitionKind transitionKind) const
{
if (isUsingSingleSlot()) {
Structure* transition = singleTransition();
- return (transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->isPropertyDeletionTransition() == !isAddition) ? transition : nullptr;
+ return (transition && transition->m_transitionPropertyName == rep && transition->transitionPropertyAttributes() == attributes && transition->transitionKind() == transitionKind) ? transition : nullptr;
}
- return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, isAddition));
+ return map()->get(StructureTransitionTable::Hash::Key(rep, attributes, transitionKind));
}
void StructureTransitionTable::add(VM& vm, Structure* structure)
@@ -114,7 +114,7 @@
}
// Add the structure to the map.
- map()->set(StructureTransitionTable::Hash::Key(structure->m_transitionPropertyName.get(), structure->transitionPropertyAttributes(), !structure->isPropertyDeletionTransition()), structure);
+ map()->set(StructureTransitionTable::Hash::Key(structure->m_transitionPropertyName.get(), structure->transitionPropertyAttributes(), structure->transitionKind()), structure);
}
void Structure::dumpStatistics()
@@ -244,6 +244,7 @@
setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
setIsQuickPropertyAccessAllowedForEnumeration(true);
setTransitionPropertyAttributes(0);
+ setTransitionKind(TransitionKind::Unknown);
setDidPreventExtensions(false);
setDidTransition(false);
setStaticPropertiesReified(false);
@@ -250,7 +251,6 @@
setTransitionWatchpointIsLikelyToBeFired(false);
setHasBeenDictionary(false);
setProtectPropertyTableWhileTransitioning(false);
- setIsPropertyDeletionTransition(false);
setTransitionOffset(vm, invalidOffset);
setMaxOffset(vm, invalidOffset);
@@ -282,6 +282,7 @@
setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
setIsQuickPropertyAccessAllowedForEnumeration(true);
setTransitionPropertyAttributes(0);
+ setTransitionKind(TransitionKind::Unknown);
setDidPreventExtensions(false);
setDidTransition(false);
setStaticPropertiesReified(false);
@@ -288,7 +289,6 @@
setTransitionWatchpointIsLikelyToBeFired(false);
setHasBeenDictionary(false);
setProtectPropertyTableWhileTransitioning(false);
- setIsPropertyDeletionTransition(false);
setTransitionOffset(vm, invalidOffset);
setMaxOffset(vm, invalidOffset);
@@ -320,12 +320,12 @@
setHasUnderscoreProtoPropertyExcludingOriginalProto(previous->hasUnderscoreProtoPropertyExcludingOriginalProto());
setIsQuickPropertyAccessAllowedForEnumeration(previous->isQuickPropertyAccessAllowedForEnumeration());
setTransitionPropertyAttributes(0);
+ setTransitionKind(TransitionKind::Unknown);
setDidPreventExtensions(previous->didPreventExtensions());
setDidTransition(true);
setStaticPropertiesReified(previous->staticPropertiesReified());
setHasBeenDictionary(previous->hasBeenDictionary());
setProtectPropertyTableWhileTransitioning(false);
- setIsPropertyDeletionTransition(false);
setTransitionOffset(vm, invalidOffset);
setMaxOffset(vm, invalidOffset);
@@ -472,8 +472,7 @@
ASSERT(!structure->isDictionary());
ASSERT(structure->isObject());
- constexpr bool isAddition = true;
- if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes, isAddition)) {
+ if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes, TransitionKind::PropertyAddition)) {
validateOffset(existingTransition->transitionOffset(), existingTransition->inlineCapacity());
offset = existingTransition->transitionOffset();
return existingTransition;
@@ -571,6 +570,7 @@
transition->m_blob.setIndexingModeIncludingHistory(structure->indexingModeIncludingHistory() & ~CopyOnWrite);
transition->m_transitionPropertyName = propertyName.uid();
transition->setTransitionPropertyAttributes(attributes);
+ transition->setTransitionKind(TransitionKind::PropertyAddition);
transition->setPropertyTable(vm, structure->takePropertyTableOrCloneIfPinned(vm));
transition->setMaxOffset(vm, structure->maxOffset());
@@ -607,9 +607,8 @@
ASSERT(!structure->isUncacheableDictionary());
ASSERT(structure->isObject());
- constexpr bool isAddition = false;
offset = invalidOffset;
- if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.uid(), attributes, isAddition)) {
+ if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.uid(), attributes, TransitionKind::PropertyDeletion)) {
validateOffset(existingTransition->transitionOffset(), existingTransition->inlineCapacity());
offset = existingTransition->transitionOffset();
return existingTransition;
@@ -667,9 +666,9 @@
transition->m_blob.setIndexingModeIncludingHistory(structure->indexingModeIncludingHistory() & ~CopyOnWrite);
transition->m_transitionPropertyName = propertyName.uid();
+ transition->setTransitionKind(TransitionKind::PropertyDeletion);
transition->setPropertyTable(vm, structure->takePropertyTableOrCloneIfPinned(vm));
transition->setMaxOffset(vm, structure->maxOffset());
- transition->setIsPropertyDeletionTransition(true);
offset = transition->remove(vm, propertyName);
ASSERT(offset != invalidOffset);
@@ -762,17 +761,17 @@
Structure* Structure::sealTransition(VM& vm, Structure* structure)
{
- return nonPropertyTransition(vm, structure, NonPropertyTransition::Seal);
+ return nonPropertyTransition(vm, structure, TransitionKind::Seal);
}
Structure* Structure::freezeTransition(VM& vm, Structure* structure)
{
- return nonPropertyTransition(vm, structure, NonPropertyTransition::Freeze);
+ return nonPropertyTransition(vm, structure, TransitionKind::Freeze);
}
Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
{
- return nonPropertyTransition(vm, structure, NonPropertyTransition::PreventExtensions);
+ return nonPropertyTransition(vm, structure, TransitionKind::PreventExtensions);
}
PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm)
@@ -790,15 +789,13 @@
return materializePropertyTable(vm, setPropertyTable);
}
-Structure* Structure::nonPropertyTransitionSlow(VM& vm, Structure* structure, NonPropertyTransition transitionKind)
+Structure* Structure::nonPropertyTransitionSlow(VM& vm, Structure* structure, TransitionKind transitionKind)
{
- unsigned attributes = toAttributes(transitionKind);
IndexingType indexingModeIncludingHistory = newIndexingType(structure->indexingModeIncludingHistory(), transitionKind);
Structure* existingTransition;
- constexpr bool isAddition = true;
- if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(nullptr, attributes, isAddition))) {
- ASSERT(existingTransition->transitionPropertyAttributes() == attributes);
+ if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(nullptr, 0, transitionKind))) {
+ ASSERT(existingTransition->transitionKind() == transitionKind);
ASSERT(existingTransition->indexingModeIncludingHistory() == indexingModeIncludingHistory);
return existingTransition;
}
@@ -806,7 +803,7 @@
DeferGC deferGC(vm.heap);
Structure* transition = create(vm, structure);
- transition->setTransitionPropertyAttributes(attributes);
+ transition->setTransitionKind(transitionKind);
transition->m_blob.setIndexingModeIncludingHistory(indexingModeIncludingHistory);
if (preventsExtensions(transitionKind))
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2020-08-14 01:56:43 UTC (rev 265640)
@@ -203,8 +203,8 @@
JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
static Structure* preventExtensionsTransition(VM&, Structure*);
- static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
- JS_EXPORT_PRIVATE static Structure* nonPropertyTransitionSlow(VM&, Structure*, NonPropertyTransition);
+ static Structure* nonPropertyTransition(VM&, Structure*, TransitionKind);
+ JS_EXPORT_PRIVATE static Structure* nonPropertyTransitionSlow(VM&, Structure*, TransitionKind);
JS_EXPORT_PRIVATE bool isSealed(VM&);
JS_EXPORT_PRIVATE bool isFrozen(VM&);
@@ -691,7 +691,7 @@
void set##upperName(type newValue) \
{\
m_bitField &= ~(s_##lowerName##Mask << offset);\
- m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
+ m_bitField |= (static_cast<uint32_t>(newValue) & s_##lowerName##Mask) << offset;\
}
DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
@@ -699,7 +699,8 @@
DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
- DEFINE_BITFIELD(unsigned, transitionPropertyAttributes, TransitionPropertyAttributes, 14, 6);
+ DEFINE_BITFIELD(TransitionPropertyAttributes, transitionPropertyAttributes, TransitionPropertyAttributes, 8, 6);
+ DEFINE_BITFIELD(TransitionKind, transitionKind, TransitionKind, 6, 14);
DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 22);
@@ -710,10 +711,13 @@
DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 27);
DEFINE_BITFIELD(bool, protectPropertyTableWhileTransitioning, ProtectPropertyTableWhileTransitioning, 1, 28);
DEFINE_BITFIELD(bool, hasUnderscoreProtoPropertyExcludingOriginalProto, HasUnderscoreProtoPropertyExcludingOriginalProto, 1, 29);
- DEFINE_BITFIELD(bool, isPropertyDeletionTransition, IsPropertyDeletionTransition, 1, 30);
static_assert(s_bitWidthOfTransitionPropertyAttributes <= sizeof(TransitionPropertyAttributes) * 8);
+ static_assert(s_bitWidthOfTransitionKind <= sizeof(TransitionKind) * 8);
+ bool isPropertyAdditionTransition() const { return transitionKind() == TransitionKind::PropertyAddition; }
+ bool isPropertyDeletionTransition() const { return transitionKind() == TransitionKind::PropertyDeletion; }
+
private:
friend class LLIntOffsetsExtractor;
Modified: trunk/Source/_javascript_Core/runtime/StructureInlines.h (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/StructureInlines.h 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/StructureInlines.h 2020-08-14 01:56:43 UTC (rev 265640)
@@ -608,7 +608,7 @@
return !aObj && !bObj;
}
-inline Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind)
+inline Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, TransitionKind transitionKind)
{
IndexingType indexingModeIncludingHistory = newIndexingType(structure->indexingModeIncludingHistory(), transitionKind);
Modified: trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h (265639 => 265640)
--- trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h 2020-08-14 00:25:56 UTC (rev 265639)
+++ trunk/Source/_javascript_Core/runtime/StructureTransitionTable.h 2020-08-14 01:56:43 UTC (rev 265640)
@@ -35,11 +35,16 @@
class JSCell;
class Structure;
-static constexpr unsigned FirstInternalAttribute = 1 << 6; // Use for transitions that don't have to do with property additions.
+using TransitionPropertyAttributes = uint8_t;
-// Support for attributes used to indicate transitions not related to properties.
-// If any of these are used, the string portion of the key should be 0.
-enum class NonPropertyTransition : unsigned {
+enum class TransitionKind : uint8_t {
+ Unknown,
+ PropertyAddition,
+ PropertyDeletion,
+ PropertyAttributeChange,
+
+ // Support for transitions not related to properties.
+ // If any of these are used, the string portion of the key should be 0.
AllocateUndecided,
AllocateInt32,
AllocateDouble,
@@ -52,24 +57,20 @@
Seal,
Freeze
};
-using TransitionPropertyAttributes = uint16_t;
-inline unsigned toAttributes(NonPropertyTransition transition)
-{
- return static_cast<unsigned>(transition) + FirstInternalAttribute;
-}
+static constexpr auto FirstNonPropertyTransitionKind = TransitionKind::AllocateUndecided;
-inline bool changesIndexingType(NonPropertyTransition transition)
+inline bool changesIndexingType(TransitionKind transition)
{
switch (transition) {
- case NonPropertyTransition::AllocateUndecided:
- case NonPropertyTransition::AllocateInt32:
- case NonPropertyTransition::AllocateDouble:
- case NonPropertyTransition::AllocateContiguous:
- case NonPropertyTransition::AllocateArrayStorage:
- case NonPropertyTransition::AllocateSlowPutArrayStorage:
- case NonPropertyTransition::SwitchToSlowPutArrayStorage:
- case NonPropertyTransition::AddIndexedAccessors:
+ case TransitionKind::AllocateUndecided:
+ case TransitionKind::AllocateInt32:
+ case TransitionKind::AllocateDouble:
+ case TransitionKind::AllocateContiguous:
+ case TransitionKind::AllocateArrayStorage:
+ case TransitionKind::AllocateSlowPutArrayStorage:
+ case TransitionKind::SwitchToSlowPutArrayStorage:
+ case TransitionKind::AddIndexedAccessors:
return true;
default:
return false;
@@ -76,31 +77,31 @@
}
}
-inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition)
+inline IndexingType newIndexingType(IndexingType oldType, TransitionKind transition)
{
switch (transition) {
- case NonPropertyTransition::AllocateUndecided:
+ case TransitionKind::AllocateUndecided:
ASSERT(!hasIndexedProperties(oldType));
return oldType | UndecidedShape;
- case NonPropertyTransition::AllocateInt32:
+ case TransitionKind::AllocateInt32:
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || oldType == CopyOnWriteArrayWithInt32);
return (oldType & ~IndexingShapeAndWritabilityMask) | Int32Shape;
- case NonPropertyTransition::AllocateDouble:
+ case TransitionKind::AllocateDouble:
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || oldType == CopyOnWriteArrayWithDouble);
return (oldType & ~IndexingShapeAndWritabilityMask) | DoubleShape;
- case NonPropertyTransition::AllocateContiguous:
+ case TransitionKind::AllocateContiguous:
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || oldType == CopyOnWriteArrayWithContiguous);
return (oldType & ~IndexingShapeAndWritabilityMask) | ContiguousShape;
- case NonPropertyTransition::AllocateArrayStorage:
+ case TransitionKind::AllocateArrayStorage:
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeAndWritabilityMask) | ArrayStorageShape;
- case NonPropertyTransition::AllocateSlowPutArrayStorage:
+ case TransitionKind::AllocateSlowPutArrayStorage:
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape;
- case NonPropertyTransition::SwitchToSlowPutArrayStorage:
+ case TransitionKind::SwitchToSlowPutArrayStorage:
ASSERT(hasArrayStorage(oldType));
return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape;
- case NonPropertyTransition::AddIndexedAccessors:
+ case TransitionKind::AddIndexedAccessors:
return oldType | MayHaveIndexedAccessors;
default:
return oldType;
@@ -107,12 +108,12 @@
}
}
-inline bool preventsExtensions(NonPropertyTransition transition)
+inline bool preventsExtensions(TransitionKind transition)
{
switch (transition) {
- case NonPropertyTransition::PreventExtensions:
- case NonPropertyTransition::Seal:
- case NonPropertyTransition::Freeze:
+ case TransitionKind::PreventExtensions:
+ case TransitionKind::Seal:
+ case TransitionKind::Freeze:
return true;
default:
return false;
@@ -119,11 +120,11 @@
}
}
-inline bool setsDontDeleteOnAllProperties(NonPropertyTransition transition)
+inline bool setsDontDeleteOnAllProperties(TransitionKind transition)
{
switch (transition) {
- case NonPropertyTransition::Seal:
- case NonPropertyTransition::Freeze:
+ case TransitionKind::Seal:
+ case TransitionKind::Freeze:
return true;
default:
return false;
@@ -130,10 +131,10 @@
}
}
-inline bool setsReadOnlyOnNonAccessorProperties(NonPropertyTransition transition)
+inline bool setsReadOnlyOnNonAccessorProperties(TransitionKind transition)
{
switch (transition) {
- case NonPropertyTransition::Freeze:
+ case TransitionKind::Freeze:
return true;
default:
return false;
@@ -146,27 +147,28 @@
#if CPU(ADDRESS64)
struct Hash {
- // Logically, Key is a tuple of (1) UniquedStringImpl*, (2) unsigned attributes, and (3) bool isAddition.
- // We encode (2) and (3) into (1)'s empty bits since a pointer is 48bit and lower 3 bits are usable because of alignment.
+ // Logically, Key is a tuple of (1) UniquedStringImpl*, (2) unsigned attributes, and (3) transitionKind.
struct Key {
friend struct Hash;
static_assert(WTF_OS_CONSTANT_EFFECTIVE_ADDRESS_WIDTH <= 48);
- static constexpr uintptr_t isAdditionMask = 1ULL;
- static constexpr uintptr_t stringMask = ((1ULL << 48) - 1) & (~isAdditionMask);
static constexpr unsigned attributesShift = 48;
+ static constexpr unsigned transitionKindShift = 56;
+ static constexpr uintptr_t stringMask = (1ULL << attributesShift) - 1;
static constexpr uintptr_t hashTableDeletedValue = 0x2;
- static_assert(sizeof(TransitionPropertyAttributes) * 8 <= 16);
+ static_assert(sizeof(TransitionPropertyAttributes) * 8 <= 8);
+ static_assert(sizeof(TransitionKind) * 8 <= 8);
static_assert(hashTableDeletedValue < alignof(UniquedStringImpl));
- // Highest 16 bits are for TransitionPropertyAttributes.
- // Lowest 1 bit is for isAddition flag.
+ // Highest 8 bits are for TransitionKind; next 8 belong to TransitionPropertyAttributes.
// Remaining bits are for UniquedStringImpl*.
- Key(UniquedStringImpl* impl, unsigned attributes, bool isAddition)
- : m_encodedData(bitwise_cast<uintptr_t>(impl) | (static_cast<uintptr_t>(attributes) << attributesShift) | (static_cast<uintptr_t>(isAddition) & isAdditionMask))
+ Key(UniquedStringImpl* impl, unsigned attributes, TransitionKind transitionKind)
+ : m_encodedData(bitwise_cast<uintptr_t>(impl) | (static_cast<uintptr_t>(attributes) << attributesShift) | (static_cast<uintptr_t>(transitionKind) << transitionKindShift))
{
ASSERT(impl == this->impl());
- ASSERT(isAddition == this->isAddition());
+ ASSERT(attributes <= UINT8_MAX);
ASSERT(attributes == this->attributes());
+ ASSERT(transitionKind != TransitionKind::Unknown);
+ ASSERT(transitionKind == this->transitionKind());
}
Key() = default;
@@ -178,8 +180,8 @@
bool isHashTableDeletedValue() const { return m_encodedData == hashTableDeletedValue; }
UniquedStringImpl* impl() const { return bitwise_cast<UniquedStringImpl*>(m_encodedData & stringMask); }
- bool isAddition() const { return m_encodedData & isAdditionMask; }
- unsigned attributes() const { return m_encodedData >> attributesShift; }
+ TransitionPropertyAttributes attributes() const { return (m_encodedData >> attributesShift) & UINT8_MAX; }
+ TransitionKind transitionKind() const { return static_cast<TransitionKind>(m_encodedData >> transitionKindShift); }
friend bool operator==(const Key& a, const Key& b)
{
@@ -210,12 +212,12 @@
};
#else
struct Hash {
- using Key = std::tuple<UniquedStringImpl*, unsigned, bool>;
+ using Key = std::tuple<UniquedStringImpl*, unsigned, TransitionKind>;
using KeyTraits = HashTraits<Key>;
static unsigned hash(const Key& p)
{
- return PtrHash<UniquedStringImpl*>::hash(std::get<0>(p)) + std::get<1>(p);
+ return PtrHash<UniquedStringImpl*>::hash(std::get<0>(p)) + std::get<1>(p) + static_cast<unsigned>(std::get<2>(p));
}
static bool equal(const Key& a, const Key& b)
@@ -249,8 +251,8 @@
}
void add(VM&, Structure*);
- bool contains(UniquedStringImpl*, unsigned attributes, bool isAddition) const;
- Structure* get(UniquedStringImpl*, unsigned attributes, bool isAddition) const;
+ bool contains(UniquedStringImpl*, unsigned attributes, TransitionKind) const;
+ Structure* get(UniquedStringImpl*, unsigned attributes, TransitionKind) const;
private:
friend class SingleSlotTransitionWeakOwner;