Bug 477279 - Tune dense array growth. r=brendan.

--HG--
extra : rebase_source : 4493d59e8bd46c1635d2f8cef39f87904d83e09f
This commit is contained in:
Jason Orendorff 2009-02-23 17:31:02 -06:00
Родитель 5d078a1c92
Коммит 272b471443
2 изменённых файлов: 51 добавлений и 18 удалений

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

@ -338,14 +338,47 @@ ResizeSlots(JSContext *cx, JSObject *obj, uint32 oldsize, uint32 size)
return JS_TRUE;
}
static JSBool
EnsureCapacity(JSContext *cx, JSObject *obj, uint32 len)
{
uint32 oldlen = js_DenseArrayCapacity(obj);
/*
* When a dense array with CAPACITY_DOUBLING_MAX or fewer slots needs to grow,
* double its capacity, to push() N elements in amortized O(N) time.
*
* Above this limit, grow by 12.5% each time. Speed is still amortized O(N),
* with a higher constant factor, and we waste less space.
*/
#define CAPACITY_DOUBLING_MAX (1024 * 1024)
if (len > oldlen) {
return ResizeSlots(cx, obj, oldlen,
len + ARRAY_GROWBY - (len % ARRAY_GROWBY));
/*
* Round up all large allocations to a multiple of this (1MB), so as not to
* waste space if malloc gives us 1MB-sized chunks (as jemalloc does).
*/
#define CAPACITY_CHUNK (1024 * 1024 / sizeof(jsval))
static JSBool
EnsureCapacity(JSContext *cx, JSObject *obj, uint32 capacity)
{
uint32 oldsize = js_DenseArrayCapacity(obj);
if (capacity > oldsize) {
/*
* If this overflows uint32, capacity is very large. nextsize will end
* up being less than capacity, the code below will thus disregard it,
* and ResizeSlots will fail.
*
* The way we use dslots[-1] forces a few +1s and -1s here. For
* example, (oldsize * 2 + 1) produces the sequence 7, 15, 31, 63, ...
* which makes the total allocation size (with dslots[-1]) a power
* of two.
*/
uint32 nextsize = (oldsize <= CAPACITY_DOUBLING_MAX)
? oldsize * 2 + 1
: oldsize + (oldsize >> 3);
capacity = JS_MAX(capacity, nextsize);
if (capacity >= CAPACITY_CHUNK)
capacity = JS_ROUNDUP(capacity + 1, CAPACITY_CHUNK) - 1; /* -1 for dslots[-1] */
else if (capacity < ARRAY_CAPACITY_MIN)
capacity = ARRAY_CAPACITY_MIN;
return ResizeSlots(cx, obj, oldsize, capacity);
}
return JS_TRUE;
}
@ -2147,7 +2180,7 @@ js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v)
return JS_FALSE;
}
if (!ResizeSlots(cx, obj, length, length + ARRAY_GROWBY))
if (!EnsureCapacity(cx, obj, length + 1))
return JS_FALSE;
}
obj->fslots[JSSLOT_ARRAY_LENGTH] = length + 1;
@ -2494,12 +2527,12 @@ array_concat(JSContext *cx, uintN argc, jsval *vp)
aobj = JS_THIS_OBJECT(cx, vp);
if (OBJ_IS_DENSE_ARRAY(cx, aobj)) {
/*
* Clone aobj but pass the minimum of its length and capacity, to handle
* a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In such a
* case we'll pass 8 (not 3) due to the ARRAY_GROWBY over-allocation
* policy, which will cause nobj to be over-allocated to 16. But in the
* normal case where length is <= capacity, nobj and aobj will have the
* same capacity.
* Clone aobj but pass the minimum of its length and capacity, to
* handle a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In
* such a case we'll pass 8 (not 3) due to ARRAY_CAPACITY_MIN, which
* will cause nobj to be over-allocated to 16. But in the normal case
* where length is <= capacity, nobj and aobj will have the same
* capacity.
*/
length = aobj->fslots[JSSLOT_ARRAY_LENGTH];
jsuint capacity = js_DenseArrayCapacity(aobj);
@ -3125,7 +3158,7 @@ JSObject* FASTCALL
js_NewUninitializedArray(JSContext* cx, JSObject* proto, uint32 len)
{
JSObject *obj = js_FastNewArrayWithLength(cx, proto, len);
if (!obj || !ResizeSlots(cx, obj, 0, JS_MAX(len, ARRAY_GROWBY)))
if (!obj || !ResizeSlots(cx, obj, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
return NULL;
return obj;
}
@ -3134,7 +3167,7 @@ js_NewUninitializedArray(JSContext* cx, JSObject* proto, uint32 len)
JS_ASSERT(JS_ON_TRACE(cx)); \
JSObject* obj = js_FastNewArray(cx, proto); \
if (obj) { \
const uint32 len = ARRAY_GROWBY; \
const uint32 len = ARRAY_CAPACITY_MIN; \
jsval* newslots = (jsval*) JS_malloc(cx, sizeof (jsval) * (len + 1)); \
if (newslots) { \
obj->dslots = newslots + 1; \

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

@ -48,6 +48,8 @@
JS_BEGIN_EXTERN_C
#define ARRAY_CAPACITY_MIN 7
/* Generous sanity-bound on length (in elements) of array initialiser. */
#define ARRAY_INIT_LIMIT JS_BIT(24)
@ -94,8 +96,6 @@ js_SetDenseArrayCapacity(JSObject *obj, uint32 capacity)
obj->dslots[-1] = (jsval) capacity;
}
#define ARRAY_GROWBY 8
extern JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);