mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
Bug 1782487 part 2 - Free dictionary slots if possible after densifying or removing properties. r=jonco
Dictionary slots currently never shrink: when removing properties we put the slots on the dictionary free list. If we know there are no slotful properties left, however, we can free the slots and reset the free list. This is mostly nice for densifying because we can usually free all slots in that case. The patch also fixes a minor issue in `NativeObject::shrinkSlots`, because this code is now used for dictionary objects for the first time. Differential Revision: https://phabricator.services.mozilla.com/D153437
This commit is contained in:
parent
a1d68e44d2
commit
1d6aa9252f
@ -384,8 +384,6 @@ void NativeObject::shrinkSlots(JSContext* cx, uint32_t oldCapacity,
|
||||
MOZ_ASSERT(newCapacity < oldCapacity);
|
||||
MOZ_ASSERT(oldCapacity == getSlotsHeader()->capacity());
|
||||
|
||||
uint32_t dictionarySpan = getSlotsHeader()->dictionarySlotSpan();
|
||||
|
||||
ObjectSlots* oldHeaderSlots = ObjectSlots::fromSlots(slots_);
|
||||
MOZ_ASSERT(oldHeaderSlots->capacity() == oldCapacity);
|
||||
|
||||
@ -395,12 +393,15 @@ void NativeObject::shrinkSlots(JSContext* cx, uint32_t oldCapacity,
|
||||
size_t nbytes = ObjectSlots::allocSize(oldCapacity);
|
||||
RemoveCellMemory(this, nbytes, MemoryUse::ObjectSlots);
|
||||
FreeSlots(cx, this, oldHeaderSlots, nbytes);
|
||||
setEmptyDynamicSlots(dictionarySpan);
|
||||
// dictionarySlotSpan is initialized to the correct value by the callers.
|
||||
setEmptyDynamicSlots(0);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(!is<ArrayObject>(), newCapacity >= SLOT_CAPACITY_MIN);
|
||||
|
||||
uint32_t dictionarySpan = getSlotsHeader()->dictionarySlotSpan();
|
||||
|
||||
uint32_t newAllocated = ObjectSlots::allocCount(newCapacity);
|
||||
|
||||
HeapSlot* allocation = ReallocateObjectBuffer<HeapSlot>(
|
||||
|
@ -678,6 +678,9 @@ class NativeObject : public JSObject {
|
||||
*/
|
||||
bool ensureSlotsForDictionaryObject(JSContext* cx, uint32_t span);
|
||||
|
||||
void maybeFreeDictionaryPropSlots(JSContext* cx, DictionaryPropMap* map,
|
||||
uint32_t mapLength);
|
||||
|
||||
[[nodiscard]] static bool toDictionaryMode(JSContext* cx,
|
||||
Handle<NativeObject*> obj);
|
||||
|
||||
|
@ -667,6 +667,28 @@ bool NativeObject::changeCustomDataPropAttributes(JSContext* cx,
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeObject::maybeFreeDictionaryPropSlots(JSContext* cx,
|
||||
DictionaryPropMap* map,
|
||||
uint32_t mapLength) {
|
||||
// We can free all non-reserved slots if there are no properties left. We also
|
||||
// handle the case where there's a single slotless property, to support arrays
|
||||
// (array.length is a custom data property).
|
||||
|
||||
MOZ_ASSERT(shape()->dictionaryPropMap() == map);
|
||||
MOZ_ASSERT(shape()->propMapLength() == mapLength);
|
||||
|
||||
if (mapLength > 1 || map->previous()) {
|
||||
return;
|
||||
}
|
||||
if (mapLength == 1 && map->getPropertyInfo(0).hasSlot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t numReserved = JSCLASS_RESERVED_SLOTS(getClass());
|
||||
MOZ_ALWAYS_TRUE(ensureSlotsForDictionaryObject(cx, numReserved));
|
||||
map->setFreeList(SHAPE_INVALID_SLOT);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool NativeObject::removeProperty(JSContext* cx, Handle<NativeObject*> obj,
|
||||
HandleId id) {
|
||||
@ -773,6 +795,15 @@ bool NativeObject::removeProperty(JSContext* cx, Handle<NativeObject*> obj,
|
||||
|
||||
obj->shape()->updateNewDictionaryShape(obj->shape()->objectFlags(), dictMap,
|
||||
mapLength);
|
||||
|
||||
// If we just deleted the last property, consider shrinking the slots. We only
|
||||
// do this if there are a lot of slots, to avoid allocating/freeing dynamic
|
||||
// slots repeatedly.
|
||||
static constexpr size_t MinSlotSpanForFree = 64;
|
||||
if (obj->dictionaryModeSlotSpan() >= MinSlotSpanForFree) {
|
||||
obj->maybeFreeDictionaryPropSlots(cx, dictMap, mapLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -800,6 +831,9 @@ bool NativeObject::densifySparseElements(JSContext* cx,
|
||||
objectFlags.clearFlag(ObjectFlag::Indexed);
|
||||
|
||||
obj->shape()->updateNewDictionaryShape(objectFlags, map, mapLength);
|
||||
|
||||
obj->maybeFreeDictionaryPropSlots(cx, map, mapLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user