Bug 957542 - Don't over-allocate dynamic slots of ArrayObject, r=bhackett,terrence

This commit is contained in:
Hannes Verschore 2014-02-10 12:33:27 +01:00
Родитель 0477dcbeb0
Коммит 4bc7ae0025
6 изменённых файлов: 45 добавлений и 27 удалений

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

@ -132,6 +132,9 @@ js::Nursery::isEmpty() const
JSObject *
js::Nursery::allocateObject(JSContext *cx, size_t size, size_t numDynamic)
{
/* Ensure there's enough space to replace the contents with a RelocationOverlay. */
JS_ASSERT(size >= sizeof(RelocationOverlay));
/* Attempt to allocate slots contiguously after object, if possible. */
if (numDynamic && numDynamic <= MaxNurserySlots) {
size_t totalSize = size + sizeof(HeapSlot) * numDynamic;
@ -166,9 +169,6 @@ js::Nursery::allocate(size_t size)
JS_ASSERT(isEnabled());
JS_ASSERT(!runtime()->isHeapBusy());
/* Ensure there's enough space to replace the contents with a RelocationOverlay. */
JS_ASSERT(size >= sizeof(RelocationOverlay));
if (position() + size > currentEnd()) {
if (currentChunk_ + 1 == numActiveChunks_)
return nullptr;

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

@ -4653,7 +4653,8 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
MInstruction *slots;
if (templateObj->hasDynamicSlots()) {
size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlotsForCompilation(),
templateObj->lastProperty()->slotSpan(templateObj->getClass()));
templateObj->lastProperty()->slotSpan(templateObj->getClass()),
templateObj->getClass());
slots = MNewSlots::New(alloc(), nslots);
} else {
slots = MConstant::New(alloc(), NullValue());

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

@ -2222,8 +2222,8 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *aArg, JSObject *bArg,
* other object.
*/
unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan());
unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan());
unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan(), b->getClass());
unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan(), a->getClass());
if (adynamic) {
reserved.newaslots = cx->pod_malloc<HeapSlot>(adynamic);
@ -2654,8 +2654,8 @@ JSObject::updateSlotsForSpan(ThreadSafeContext *cx,
JS_ASSERT(cx->isThreadLocal(obj));
JS_ASSERT(oldSpan != newSpan);
size_t oldCount = dynamicSlotsCount(obj->numFixedSlots(), oldSpan);
size_t newCount = dynamicSlotsCount(obj->numFixedSlots(), newSpan);
size_t oldCount = dynamicSlotsCount(obj->numFixedSlots(), oldSpan, obj->getClass());
size_t newCount = dynamicSlotsCount(obj->numFixedSlots(), newSpan, obj->getClass());
if (oldSpan < newSpan) {
if (oldCount < newCount && !JSObject::growSlots(cx, obj, oldCount, newCount))
@ -2748,7 +2748,7 @@ JSObject::growSlots(ThreadSafeContext *cx, HandleObject obj, uint32_t oldCount,
{
JS_ASSERT(cx->isThreadLocal(obj));
JS_ASSERT(newCount > oldCount);
JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
JS_ASSERT_IF(!obj->is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
/*
* Slot capacities are determined by the span of allocated objects. Due to
@ -2834,7 +2834,7 @@ JSObject::shrinkSlots(ThreadSafeContext *cx, HandleObject obj, uint32_t oldCount
return;
}
JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
JS_ASSERT_IF(!obj->is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
// Global slots may be read during off thread compilation, and updates to
// their slot pointers need to be synchronized.

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

@ -497,9 +497,14 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()));
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
type->clasp()));
const js::Class *clasp = type->clasp();
size_t nDynamicSlots = 0;
if (!extantSlots)
nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
size_t nDynamicSlots = extantSlots ? 0 : dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan());
JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap);
if (!obj)
return nullptr;
@ -510,7 +515,6 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
obj->slots = extantSlots;
obj->elements = js::emptyObjectElements;
const js::Class *clasp = type->clasp();
if (clasp->hasPrivate())
obj->privateRef(shape->numFixedSlots()) = nullptr;
@ -537,7 +541,7 @@ JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::
* named properties stored in those fixed slots.
*/
JS_ASSERT(shape->numFixedSlots() == 0);
size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan());
size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), type->clasp());
JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap);
if (!obj)
return nullptr;

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

@ -353,6 +353,24 @@ js::ObjectImpl::numFixedSlotsForCompilation() const
return gc::GetGCKindSlots(kind, getClass());
}
uint32_t
js::ObjectImpl::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp)
{
if (span <= nfixed)
return 0;
span -= nfixed;
// Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood
// the dynamic slots need to get increased again. ArrayObjects ignore
// this because slots are uncommon in that case.
if (clasp != &ArrayObject::class_ && span <= SLOT_CAPACITY_MIN)
return SLOT_CAPACITY_MIN;
uint32_t slots = mozilla::RoundUpPow2(span);
MOZ_ASSERT(slots >= span);
return slots;
}
void
js::ObjectImpl::markChildren(JSTracer *trc)
{

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

@ -1149,7 +1149,11 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
#endif
/* Minimum size for dynamically allocated slots. */
/*
* Minimum size for dynamically allocated slots in normal Objects.
* ArrayObjects don't use this limit and can have a lower slot capacity,
* since they normally don't have a lot of slots.
*/
static const uint32_t SLOT_CAPACITY_MIN = 8;
HeapSlot *fixedSlots() const {
@ -1239,9 +1243,10 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
/* Compute dynamicSlotsCount() for this object. */
uint32_t numDynamicSlots() const {
return dynamicSlotsCount(numFixedSlots(), slotSpan());
return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
}
Shape *nativeLookup(ExclusiveContext *cx, jsid id);
Shape *nativeLookup(ExclusiveContext *cx, PropertyId pid) {
return nativeLookup(cx, pid.asId());
@ -1406,17 +1411,7 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
* capacity is not stored explicitly, and the allocated size of the slot
* array is kept in sync with this count.
*/
static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span) {
if (span <= nfixed)
return 0;
span -= nfixed;
if (span <= SLOT_CAPACITY_MIN)
return SLOT_CAPACITY_MIN;
uint32_t slots = mozilla::RoundUpPow2(span);
MOZ_ASSERT(slots >= span);
return slots;
}
static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp);
/* Memory usage functions. */
size_t tenuredSizeOfThis() const {