зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
22628aba16
Коммит
a50657a013
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче