bug 603318 - make dense array slow during array growth, not during the GC. r=bhackett

This commit is contained in:
Igor Bukanov 2010-10-14 16:12:19 +02:00
parent 96c95689e6
commit f110aa58b7
9 changed files with 414 additions and 148 deletions

View File

@ -0,0 +1,185 @@
// test dense -> slow array transitions during the recording and on trace
// for various array functions and property accessors
function test_set_elem() {
function f() {
var bag = [];
for (var i = 0; i != 100; ++i) {
var a = [0];
a[100*100] = i;
bag.push(a);
}
for (var i = 0; i != 100; ++i) {
var a = [0];
a[200 + i] = i;
bag.push(a);
}
return bag;
}
var bag = f();
for (var i = 0; i != 100; ++i) {
var a = bag[i];
assertEq(a.length, 100 * 100 + 1);
assertEq(a[100*100], i);
assertEq(a[0], 0);
assertEq(1 + i in a, false);
}
for (var i = 0; i != 100; ++i) {
var a = bag[100 + i];
assertEq(a.length, 200 + i + 1);
assertEq(a[200 + i], i);
assertEq(a[0], 0);
assertEq(1 + i in a, false);
}
}
function test_reverse() {
function prepare_arays() {
var bag = [];
var base_index = 245;
for (var i = 0; i != 50; ++i) {
var a = [1, 2, 3, 4, 5];
a.length = i + base_index;
bag.push(a);
}
return bag;
}
function test(bag) {
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
a.reverse();
a[0] = 1;
}
}
var bag = prepare_arays();
test(bag);
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
assertEq(a[0], 1);
for (var j = 1; j <= 5; ++j) {
assertEq(a[a.length - j], j);
}
for (var j = 1; j < a.length - 5; ++j) {
assertEq(j in a, false);
}
}
}
function test_push() {
function prepare_arays() {
var bag = [];
var base_index = 245;
for (var i = 0; i != 50; ++i) {
var a = [0];
a.length = i + base_index;
bag.push(a);
}
return bag;
}
function test(bag) {
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
a.push(2);
a[0] = 1;
}
}
var bag = prepare_arays();
test(bag);
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
assertEq(a[0], 1);
assertEq(a[a.length - 1], 2);
for (var j = 1; j < a.length - 1; ++j) {
assertEq(j in a, false);
}
}
}
function test_unshift() {
function prepare_arays() {
var bag = [];
var base_index = 245;
for (var i = 0; i != 50; ++i) {
var a = [0];
a.length = i + base_index;
bag.push(a);
}
return bag;
}
function test(bag) {
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
a.unshift(1);
a[2] = 2;
}
}
var bag = prepare_arays();
test(bag);
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
assertEq(a[0], 1);
assertEq(a[1], 0);
assertEq(a[2], 2);
for (var j = 3; j < a.length; ++j) {
assertEq(j in a, false);
}
}
}
function test_splice() {
function prepare_arays() {
var bag = [];
var base_index = 245;
for (var i = 0; i != 50; ++i) {
var a = [1, 2];
a.length = i + base_index;
bag.push(a);
}
return bag;
}
function test(bag) {
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
a.splice(1, 0, "a", "b", "c");
a[2] = 100;
}
}
var bag = prepare_arays();
test(bag);
for (var i = 0; i != bag.length; ++i) {
var a = bag[i];
assertEq(a[0], 1);
assertEq(a[1], "a");
assertEq(a[2], 100);
assertEq(a[3], "c");
assertEq(a[4], 2);
for (var j = 5; j < a.length; ++j) {
assertEq(j in a, false);
}
}
}
test_set_elem();
test_reverse();
test_push();
test_unshift();
test_splice();

View File

@ -62,9 +62,9 @@
*
* Arrays are converted to use js_SlowArrayClass when any of these conditions
* are met:
* - the load factor (COUNT / capacity) is less than 0.25, and there are
* more than MIN_SPARSE_INDEX slots total
* - a property is set that is not indexed (and not "length"); or
* - there are more than MIN_SPARSE_INDEX slots total
* - the load factor (COUNT / capacity) is less than 0.25
* - a property is set that is not indexed (and not "length")
* - a property is defined that has non-default property attributes.
*
* Dense arrays do not track property creation order, so unlike other native
@ -115,30 +115,6 @@ using namespace js::gc;
#define MAXINDEX 4294967295u
#define MAXSTR "4294967295"
/*
* Use the limit on number of object slots for sanity and consistency (see the
* assertion in JSObject::makeDenseArraySlow).
*/
static inline bool
INDEX_TOO_BIG(jsuint index)
{
return index >= JSObject::NSLOTS_LIMIT;
}
static inline bool
INDEX_TOO_SPARSE(JSObject *array, jsuint index)
{
/* Small arrays with less than 256 elements are dense, no matter what. */
if (index < 256)
return false;
/*
* Otherwise if the index becomes too large or is more than 256 past
* the current capacity, we have to slowify.
*/
return INDEX_TOO_BIG(index) || (index > array->getDenseArrayCapacity() + 256);
}
static inline bool
ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
{
@ -310,6 +286,34 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
return JS_TRUE;
}
bool
JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
uintN cap = numSlots();
JS_ASSERT(requiredCapacity >= cap);
if (requiredCapacity >= JSObject::NSLOTS_LIMIT)
return true;
uintN minimalDenseCount = requiredCapacity / 4;
if (newElementsHint >= minimalDenseCount)
return false;
minimalDenseCount -= newElementsHint;
if (minimalDenseCount > cap)
return true;
Value *elems = getDenseArrayElements();
for (uintN i = 0; i < cap; i++) {
if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
return false;
}
return true;
}
static bool
ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp)
{
@ -439,19 +443,23 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v)
if (obj->isDenseArray()) {
/* Predicted/prefetched code should favor the remains-dense case. */
if (index <= jsuint(-1)) {
JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
do {
if (index > jsuint(-1))
break;
jsuint idx = jsuint(index);
if (!INDEX_TOO_SPARSE(obj, idx)) {
JS_ASSERT(idx + 1 > idx);
if (!obj->ensureDenseArrayElements(cx, idx + 1))
return JS_FALSE;
if (idx >= obj->getArrayLength())
obj->setArrayLength(idx + 1);
obj->setDenseArrayElement(idx, v);
return JS_TRUE;
}
}
result = obj->ensureDenseArrayElements(cx, idx, 1);
if (result != JSObject::ED_OK)
break;
if (idx >= obj->getArrayLength())
obj->setArrayLength(idx + 1);
obj->setDenseArrayElement(idx, v);
return true;
} while (false);
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
if (!obj->makeDenseArraySlow(cx))
return JS_FALSE;
}
@ -474,13 +482,7 @@ js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
Class *origObjClasp = obj->clasp;
#endif
jsuint u = jsuint(i);
jsuint capacity = obj->getDenseArrayCapacity();
if (u < capacity)
return true;
if (INDEX_TOO_SPARSE(obj, u))
return false;
JSBool ret = obj->ensureDenseArrayElements(cx, u + 1);
JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK);
/* Partially check the CallInfo's storeAccSet is correct. */
JS_ASSERT(obj->clasp == origObjClasp);
@ -801,20 +803,29 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
if (!obj->isDenseArray())
return js_SetProperty(cx, obj, id, vp, strict);
if (!js_IdIsIndex(id, &i) || js_PrototypeHasIndexedProperties(cx, obj) ||
INDEX_TOO_SPARSE(obj, i)) {
if (!obj->makeDenseArraySlow(cx))
return false;
return js_SetProperty(cx, obj, id, vp, strict);
}
do {
if (!js_IdIsIndex(id, &i))
break;
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
if (!obj->ensureDenseArrayElements(cx, i + 1))
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
if (i >= obj->getArrayLength())
obj->setArrayLength(i + 1);
obj->setDenseArrayElement(i, *vp);
return true;
} while (false);
if (!obj->makeDenseArraySlow(cx))
return false;
if (i >= obj->getArrayLength())
obj->setArrayLength(i + 1);
obj->setDenseArrayElement(i, *vp);
return true;
return js_SetProperty(cx, obj, id, vp, strict);
}
static JSBool
@ -861,7 +872,7 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
return JS_TRUE;
isIndex = js_IdIsIndex(id, &i);
if (!isIndex || attrs != JSPROP_ENUMERATE || !obj->isDenseArray() || INDEX_TOO_SPARSE(obj, i)) {
if (!isIndex || attrs != JSPROP_ENUMERATE) {
if (!ENSURE_SLOW_ARRAY(cx, obj))
return JS_FALSE;
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
@ -915,20 +926,9 @@ array_trace(JSTracer *trc, JSObject *obj)
{
JS_ASSERT(obj->isDenseArray());
size_t holes = 0;
uint32 capacity = obj->getDenseArrayCapacity();
for (uint32 i = 0; i < capacity; i++) {
Value v = obj->getDenseArrayElement(i);
if (v.isMagic(JS_ARRAY_HOLE))
++holes;
else
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
}
if (IS_GC_MARKING_TRACER(trc) && holes > MIN_SPARSE_INDEX && holes > capacity / 4 * 3) {
/* This might fail, in which case we don't slowify it. */
static_cast<GCMarker *>(trc)->arraysToSlowify.append(obj);
}
for (uint32 i = 0; i < capacity; i++)
MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems");
}
static JSBool
@ -1379,22 +1379,28 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Valu
* Optimize for dense arrays so long as adding the given set of elements
* wouldn't otherwise make the array slow.
*/
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
start <= MAXINDEX - count && !INDEX_TOO_BIG(start + count)) {
do {
if (!obj->isDenseArray())
break;
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, start, count);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
jsuint newlen = start + count;
JS_ASSERT(jsdouble(start) + count == jsdouble(newlen));
if (!obj->ensureDenseArrayElements(cx, newlen))
return JS_FALSE;
if (newlen > obj->getArrayLength())
obj->setArrayLength(newlen);
JS_ASSERT(count < uint32(-1) / sizeof(Value));
memcpy(obj->getDenseArrayElements() + start, vector, sizeof(jsval) * count);
JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE));
return JS_TRUE;
}
return true;
} while (false);
Value* end = vector + count;
while (vector != end && start < MAXINDEX) {
@ -1436,7 +1442,9 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
obj->setArrayLength(length);
if (!vector || !length)
return true;
if (!obj->ensureDenseArrayElements(cx, length))
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj->ensureSlots(cx, length))
return false;
memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value));
return true;
@ -1470,7 +1478,12 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
vp->setObject(*obj);
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
do {
if (!obj->isDenseArray())
break;
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
/* An empty array or an array with no elements is already reversed. */
if (len == 0 || obj->getDenseArrayCapacity() == 0)
return JS_TRUE;
@ -1484,8 +1497,13 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
* holes in the array at its start) and ensure that the capacity is
* sufficient to hold all the elements in the array if it were full.
*/
if (!obj->ensureDenseArrayElements(cx, len))
return JS_FALSE;
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, len, 0);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
uint32 lo = 0, hi = len - 1;
for (; lo < hi; lo++, hi--) {
@ -1500,7 +1518,7 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
* holes).
*/
return JS_TRUE;
}
} while (false);
AutoValueRooter tvr(cx);
for (jsuint i = 0, half = len / 2; i < half; i++) {
@ -2005,21 +2023,27 @@ static JSBool
array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
{
uint32 length = obj->getArrayLength();
if (INDEX_TOO_SPARSE(obj, length)) {
if (!obj->makeDenseArraySlow(cx))
return JS_FALSE;
Value tmp = v;
return array_push_slowly(cx, obj, 1, &tmp, rval);
}
do {
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
if (!obj->ensureDenseArrayElements(cx, length + 1))
return JS_FALSE;
obj->setArrayLength(length + 1);
obj->setArrayLength(length + 1);
JS_ASSERT(obj->getDenseArrayElement(length).isMagic(JS_ARRAY_HOLE));
obj->setDenseArrayElement(length, v);
rval->setNumber(obj->getArrayLength());
return JS_TRUE;
JS_ASSERT(obj->getDenseArrayElement(length).isMagic(JS_ARRAY_HOLE));
obj->setDenseArrayElement(length, v);
rval->setNumber(obj->getArrayLength());
return true;
} while (false);
if (!obj->makeDenseArraySlow(cx))
return false;
Value tmp = v;
return array_push_slowly(cx, obj, 1, &tmp, rval);
}
JS_ALWAYS_INLINE JSBool
@ -2036,8 +2060,13 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
return JS_FALSE;
}
if (!obj->ensureDenseArrayElements(cx, length + 1))
return JS_FALSE;
/*
* Array comprehension cannot add holes to the array and never leaks
* the array before it is fully initialized. So we can use ensureSlots
* instead of ensureDenseArrayElements.
*/
if (!obj->ensureSlots(cx, length + 1))
return false;
}
obj->setArrayLength(length + 1);
obj->setDenseArrayElement(length, v);
@ -2195,16 +2224,27 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
/* Slide up the array to make room for argc at the bottom. */
argv = JS_ARGV(cx, vp);
if (length > 0) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!INDEX_TOO_SPARSE(obj, unsigned(newlen + argc))) {
JS_ASSERT(newlen + argc == length + argc);
if (!obj->ensureDenseArrayElements(cx, length + argc))
return JS_FALSE;
bool optimized = false;
do {
if (!obj->isDenseArray())
break;
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, argc);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
Value *elems = obj->getDenseArrayElements();
memmove(elems + argc, elems, length * sizeof(jsval));
for (uint32 i = 0; i < argc; i++)
obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
} else {
optimized = true;
} while (false);
if (!optimized) {
last = length;
jsdouble upperIndex = last + argc;
AutoValueRooter tvr(cx);
@ -2324,12 +2364,23 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
if (argc > count) {
delta = (jsuint)argc - count;
last = length;
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
length <= obj->getDenseArrayCapacity() &&
(length == 0 || !obj->getDenseArrayElement(length - 1).isMagic(JS_ARRAY_HOLE))) {
if (!obj->ensureDenseArrayElements(cx, length + delta))
return JS_FALSE;
bool optimized = false;
do {
if (!obj->isDenseArray())
break;
if (js_PrototypeHasIndexedProperties(cx, obj))
break;
if (length > obj->getDenseArrayCapacity())
break;
if (length != 0 && obj->getDenseArrayElement(length - 1).isMagic(JS_ARRAY_HOLE))
break;
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, delta);
if (result != JSObject::ED_OK) {
if (result == JSObject::ED_FAILED)
return false;
JS_ASSERT(result == JSObject::ED_SPARSE);
break;
}
Value *arraybeg = obj->getDenseArrayElements();
Value *srcbeg = arraybeg + last - 1;
Value *srcend = arraybeg + end - 1;
@ -2338,7 +2389,10 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
*dst = *src;
obj->setArrayLength(obj->getArrayLength() + delta);
} else {
optimized = true;
} while (false);
if (!optimized) {
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
@ -2979,7 +3033,9 @@ js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
JSObject *obj = js_NewEmptyArray(cx, proto, len);
if (!obj)
return NULL;
if (!obj->ensureDenseArrayElements(cx, len))
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj->ensureSlots(cx, len))
return NULL;
return obj;
}

View File

@ -46,6 +46,46 @@
#include "jspubtd.h"
#include "jsobj.h"
/* Small arrays are dense, no matter what. */
const uintN MIN_SPARSE_INDEX = 256;
inline JSObject::EnsureDenseResult
JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
{
JS_ASSERT(isDenseArray());
uintN currentCapacity = numSlots();
uintN requiredCapacity;
if (extra == 1) {
/* Optimize for the common case. */
if (index < currentCapacity)
return ED_OK;
requiredCapacity = index + 1;
if (requiredCapacity == 0) {
/* Overflow. */
return ED_SPARSE;
}
} else {
requiredCapacity = index + extra;
if (requiredCapacity < index) {
/* Overflow. */
return ED_SPARSE;
}
if (requiredCapacity <= currentCapacity)
return ED_OK;
}
/*
* We use the extra argument also as a hint about number of non-hole
* elements to be inserted.
*/
if (requiredCapacity > MIN_SPARSE_INDEX &&
willBeSparseDenseArray(requiredCapacity, extra)) {
return ED_SPARSE;
}
return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
}
extern JSBool
js_StringIsIndex(JSString *str, jsuint *indexp);
@ -144,9 +184,6 @@ js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
extern JSObject *
js_NewSlowArrayObject(JSContext *cx);
/* Minimum size at which a dense array can be made sparse. */
const uint32 MIN_SPARSE_INDEX = 256;
extern JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);

View File

@ -6809,12 +6809,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
}
#endif /* JS_HAS_GENERATORS */
/*
* Use the slower NEWINIT for arrays in scripts containing sharps, and when
* the array length exceeds MIN_SPARSE_INDEX and can be slowified during GC.
* :FIXME: bug 607825 handle slowify case.
*/
if (cg->hasSharps() || pn->pn_count >= MIN_SPARSE_INDEX) {
/* Use the slower NEWINIT for arrays in scripts containing sharps. */
if (cg->hasSharps()) {
if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum))
return JS_FALSE;
} else {

View File

@ -1374,16 +1374,6 @@ GCMarker::markDelayedChildren()
JS_ASSERT(!unmarkedArenaStackTop);
}
void
GCMarker::slowifyArrays()
{
while (!arraysToSlowify.empty()) {
JSObject *obj = arraysToSlowify.back();
arraysToSlowify.popBack();
if (obj->isMarked())
obj->makeDenseArraySlow(context);
}
}
} /* namespace js */
static void
@ -2243,9 +2233,6 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
*/
js_SweepScriptFilenames(rt);
/* Slowify arrays we have accumulated. */
gcmarker.slowifyArrays();
/*
* Destroy arenas after we finished the sweeping so finalizers can safely
* use js_IsAboutToBeFinalized().

View File

@ -983,8 +983,6 @@ struct GCMarker : public JSTracer {
void dumpConservativeRoots();
#endif
js::Vector<JSObject *, 0, js::SystemAllocPolicy> arraysToSlowify;
public:
explicit GCMarker(JSContext *cx);
~GCMarker();
@ -1005,8 +1003,6 @@ struct GCMarker : public JSTracer {
void delayMarkingChildren(void *thing);
JS_FRIEND_API(void) markDelayedChildren();
void slowifyArrays();
};
void

View File

@ -5911,7 +5911,8 @@ BEGIN_CASE(JSOP_NEWARRAY)
unsigned count = GET_UINT24(regs.pc);
JSObject *obj = js_NewArrayObject(cx, count, NULL);
if (!obj || !obj->ensureDenseArrayElements(cx, count))
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj || !obj->ensureSlots(cx, count))
goto error;
PUSH_OBJECT(*obj);

View File

@ -750,9 +750,24 @@ struct JSObject : js::gc::Cell {
inline const js::Value &getDenseArrayElement(uintN idx);
inline js::Value* addressOfDenseArrayElement(uintN idx);
inline void setDenseArrayElement(uintN idx, const js::Value &val);
inline bool ensureDenseArrayElements(JSContext *cx, uintN cap);
inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
/*
* ensureDenseArrayElements ensures that the dense array can hold at least
* index + extra elements. It returns ED_OK on success, ED_FAILED on
* failure to grow the array, ED_SPARSE when the array is too sparse to
* grow (this includes the case of index + extra overflow). In the last
* two cases the array is kept intact.
*/
enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
inline EnsureDenseResult ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra);
/*
* Check if after growing the dense array will be too sparse.
* newElementsHint is an estimated number of elements to be added.
*/
bool willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint);
JSBool makeDenseArraySlow(JSContext *cx);
/*

View File

@ -329,13 +329,6 @@ JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
setSlot(idx, val);
}
inline bool
JSObject::ensureDenseArrayElements(JSContext *cx, uintN cap)
{
JS_ASSERT(isDenseArray());
return ensureSlots(cx, cap);
}
inline void
JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
{