Bug 1663741 - Fix problems updating slots after swapping objects r=jandem

This does two things: avoid triggering an assertion about the number of dynamic slots while the object is in an intermidiate state, and preserve the number of dictionary mode slots when reallocating the dynamic slots.

Differential Revision: https://phabricator.services.mozilla.com/D89630
This commit is contained in:
Jon Coppeard 2020-09-10 09:18:39 +00:00
Родитель 22628aba16
Коммит a50657a013
2 изменённых файлов: 41 добавлений и 5 удалений

Просмотреть файл

@ -0,0 +1,29 @@
const thisGlobal = this;
const otherGlobalSameCompartment = newGlobal({sameCompartmentAs: thisGlobal});
const otherGlobalNewCompartment = newGlobal({newCompartment: true});
const globals = [thisGlobal, otherGlobalSameCompartment, otherGlobalNewCompartment];
function testProperties(global, count) {
let {object: source, transplant} = transplantableObject();
// Create a bunch properties on |source|, which force allocation of dynamic
// slots.
for (let i = 0; i < count; i++) {
source["foo" + i] = i;
}
// Calling |transplant| transplants the object and then returns undefined.
transplant(global);
// Check the properties were copied over to the swapped object.
for (let i = 0; i < count; i++) {
assertEq(source["foo" + i], i);
}
}
for (let global of globals) {
for (let count of [0, 10, 30]) {
testProperties(global, count);
}
}

Просмотреть файл

@ -1487,25 +1487,32 @@ bool NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj,
MOZ_ASSERT(!priv);
}
uint32_t oldDictionarySlotSpan =
obj->inDictionaryMode() ? obj->dictionaryModeSlotSpan() : 0;
Zone* zone = obj->zone();
if (obj->hasDynamicSlots()) {
ObjectSlots* slotsHeader = obj->getSlotsHeader();
uint32_t oldDictionarySlotSpan = slotsHeader->dictionarySlotSpan();
size_t size = ObjectSlots::allocSize(slotsHeader->capacity());
zone->removeCellMemory(old, size, MemoryUse::ObjectSlots);
js_free(slotsHeader);
obj->setEmptyDynamicSlots(oldDictionarySlotSpan);
obj->setEmptyDynamicSlots(0);
}
size_t ndynamic =
calculateDynamicSlots(nfixed, values.length(), obj->getClass());
MOZ_ASSERT(ndynamic >= obj->numDynamicSlots());
if (ndynamic > obj->numDynamicSlots()) {
if (!obj->growSlots(cx, obj->numDynamicSlots(), ndynamic)) {
size_t currentSlots = obj->getSlotsHeader()->capacity();
MOZ_ASSERT(ndynamic >= currentSlots);
if (ndynamic > currentSlots) {
if (!obj->growSlots(cx, currentSlots, ndynamic)) {
return false;
}
}
if (obj->inDictionaryMode()) {
obj->setDictionaryModeSlotSpan(oldDictionarySlotSpan);
}
obj->initSlotRange(0, values.begin(), values.length());
return true;