Bug 479566 - Rename array "dense length" to capacity. r=shaver.
authorJason Orendorff <jorendorff@mozilla.com>
Sat, 21 Feb 2009 15:33:50 -0600
changeset 25475 91822404cf911b829a20f1a7cfc4dba265c212a0
parent 25474 7aee91307a9f540b32e70f29208ac5d1665b8811
child 25476 a7d59e4a7b192dedc0ffbd22de1fea072368aa13
push id5575
push userrsayre@mozilla.com
push dateWed, 25 Feb 2009 09:05:38 +0000
treeherdermozilla-central@8eba35e62d92 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshaver
bugs479566
milestone1.9.2a1pre
Bug 479566 - Rename array "dense length" to capacity. r=shaver.
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jstracer.cpp
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -44,41 +44,37 @@
  * Array objects begin as "dense" arrays, optimized for numeric-only property
  * access over a vector of slots (obj->dslots) with high load factor.  Array
  * methods optimize for denseness by testing that the object's class is
  * &js_ArrayClass, and can then directly manipulate the slots for efficiency.
  *
  * We track these pieces of metadata for arrays in dense mode:
  *  - the array's length property as a uint32, in JSSLOT_ARRAY_LENGTH,
  *  - the number of indices that are filled (non-holes), in JSSLOT_ARRAY_COUNT,
- *  - the net number of slots starting at dslots (DENSELEN), in dslots[-1] if
+ *  - the net number of slots starting at dslots (capacity), in dslots[-1] if
  *    dslots is non-NULL.
  *
  * In dense mode, holes in the array are represented by JSVAL_HOLE.  The final
  * slot in fslots (JSSLOT_ARRAY_LOOKUP_HOLDER) is used to store the single jsid
  * "in use" by a lookupProperty caller.
  *
  * Arrays are converted to use js_SlowArrayClass when any of these conditions
  * are met:
- *  - the load factor (COUNT / DENSELEN) is less than 0.25, and there are
+ *  - 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 non-numeric (and not "length"); or
- *  - a hole is filled below DENSELEN (possibly implicitly through methods like
- *    |reverse| or |splice|).
+ *  - a property is defined that has non-default property attributes.
  *
- * In the latter two cases, property creation order is no longer index order,
- * which necessitates use of a structure that keeps track of property creation
- * order.  (ES4, due to expectations baked into web script, requires that
- * enumeration order be the order in which properties were created.)
- *
- * An alternative in the latter case (out-of-order index set) would be to
- * maintain the scope to track property enumeration order, but still use
- * the fast slot access.  That would have the same memory cost as just using
- * a js_SlowArrayClass, but have the same performance characteristics as
- * a dense array for slot accesses, at some cost in code complexity.
+ * Dense arrays do not track property creation order, so unlike other native
+ * objects and slow arrays, enumerating an array does not necessarily visit the
+ * properties in the order they were created.  We could instead maintain the
+ * scope to track property enumeration order, but still use the fast slot
+ * access.  That would have the same memory cost as just using a
+ * js_SlowArrayClass, but have the same performance characteristics as a dense
+ * array for slot accesses, at some cost in code complexity.
  */
 #include "jsstddef.h"
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsutil.h" /* Added by JSIFY */
 #include "jsapi.h"
 #include "jsarray.h"
@@ -105,17 +101,17 @@
 #define MAXSTR   "4294967295"
 
 /* Small arrays are dense, no matter what. */
 #define MIN_SPARSE_INDEX 32
 
 #define INDEX_TOO_BIG(index) ((index) > JS_BIT(29) - 1)
 #define INDEX_TOO_SPARSE(array, index)                                         \
     (INDEX_TOO_BIG(index) ||                                                   \
-     ((index) > ARRAY_DENSE_LENGTH(array) && (index) >= MIN_SPARSE_INDEX &&    \
+     ((index) > js_DenseArrayCapacity(array) && (index) >= MIN_SPARSE_INDEX && \
       (index) > (uint32)((array)->fslots[JSSLOT_ARRAY_COUNT] + 1) * 4))
 
 JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval));
 
 #define ENSURE_SLOW_ARRAY(cx, obj)                                             \
     (OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass || js_MakeArraySlow(cx, obj))
 
 /*
@@ -307,51 +303,51 @@ BigIndexToId(JSContext *cx, JSObject *ob
             return JS_FALSE;
     }
 
     *idp = ATOM_TO_JSID(atom);
     return JS_TRUE;
 }
 
 static JSBool
-ResizeSlots(JSContext *cx, JSObject *obj, uint32 oldlen, uint32 len)
+ResizeSlots(JSContext *cx, JSObject *obj, uint32 oldsize, uint32 size)
 {
     jsval *slots, *newslots;
 
-    if (len == 0) {
+    if (size == 0) {
         if (obj->dslots) {
             JS_free(cx, obj->dslots - 1);
             obj->dslots = NULL;
         }
         return JS_TRUE;
     }
 
-    if (len > ~(uint32)0 / sizeof(jsval)) {
+    if (size > ~(uint32)0 / sizeof(jsval)) {
         js_ReportAllocationOverflow(cx);
         return JS_FALSE;
     }
 
     slots = obj->dslots ? obj->dslots - 1 : NULL;
-    newslots = (jsval *) JS_realloc(cx, slots, sizeof (jsval) * (len + 1));
+    newslots = (jsval *) JS_realloc(cx, slots, sizeof (jsval) * (size + 1));
     if (!newslots)
         return JS_FALSE;
 
     obj->dslots = newslots + 1;
-    ARRAY_SET_DENSE_LENGTH(obj, len);
-
-    for (slots = obj->dslots + oldlen; slots < obj->dslots + len; slots++)
+    js_SetDenseArrayCapacity(obj, size);
+
+    for (slots = obj->dslots + oldsize; slots < obj->dslots + size; slots++)
         *slots = JSVAL_HOLE;
 
     return JS_TRUE;
 }
 
 static JSBool
-EnsureLength(JSContext *cx, JSObject *obj, uint32 len)
+EnsureCapacity(JSContext *cx, JSObject *obj, uint32 len)
 {
-    uint32 oldlen = ARRAY_DENSE_LENGTH(obj);
+    uint32 oldlen = js_DenseArrayCapacity(obj);
 
     if (len > oldlen) {
         return ResizeSlots(cx, obj, oldlen,
                            len + ARRAY_GROWBY - (len % ARRAY_GROWBY));
     }
     return JS_TRUE;
 }
 
@@ -364,17 +360,17 @@ EnsureLength(JSContext *cx, JSObject *ob
 static JSBool
 GetArrayElement(JSContext *cx, JSObject *obj, jsuint index, JSBool *hole,
                 jsval *vp)
 {
     jsid id;
     JSObject *obj2;
     JSProperty *prop;
 
-    if (OBJ_IS_DENSE_ARRAY(cx, obj) && index < ARRAY_DENSE_LENGTH(obj) &&
+    if (OBJ_IS_DENSE_ARRAY(cx, obj) && index < js_DenseArrayCapacity(obj) &&
         (*vp = obj->dslots[index]) != JSVAL_HOLE) {
         *hole = JS_FALSE;
         return JS_TRUE;
     }
 
     if (index <= JSVAL_INT_MAX) {
         id = INT_TO_JSID(index);
     } else {
@@ -407,17 +403,17 @@ GetArrayElement(JSContext *cx, JSObject 
 static JSBool
 SetArrayElement(JSContext *cx, JSObject *obj, jsuint index, jsval v)
 {
     jsid id;
 
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
         /* Predicted/prefeched code should favor the remains-dense case. */
         if (!INDEX_TOO_SPARSE(obj, index)) {
-            if (!EnsureLength(cx, obj, index + 1))
+            if (!EnsureCapacity(cx, obj, index + 1))
                 return JS_FALSE;
             if (index >= (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH])
                 obj->fslots[JSSLOT_ARRAY_LENGTH] = index + 1;
             if (obj->dslots[index] == JSVAL_HOLE)
                 obj->fslots[JSSLOT_ARRAY_COUNT]++;
             obj->dslots[index] = v;
             return JS_TRUE;
         }
@@ -438,17 +434,17 @@ SetArrayElement(JSContext *cx, JSObject 
 
 static JSBool
 DeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index)
 {
     jsid id;
     jsval junk;
 
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
-        if (index < ARRAY_DENSE_LENGTH(obj)) {
+        if (index < js_DenseArrayCapacity(obj)) {
             if (obj->dslots[index] != JSVAL_HOLE)
                 obj->fslots[JSSLOT_ARRAY_COUNT]--;
             obj->dslots[index] = JSVAL_HOLE;
         }
         return JS_TRUE;
     }
 
     if (index <= JSVAL_INT_MAX) {
@@ -576,17 +572,17 @@ array_length_setter(JSContext *cx, JSObj
 
     if (oldlen < newlen) {
         obj->fslots[JSSLOT_ARRAY_LENGTH] = newlen;
         return JS_TRUE;
     }
 
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
         /* Don't reallocate if we're not actually shrinking our slots. */
-        jsuint oldsize = ARRAY_DENSE_LENGTH(obj);
+        jsuint oldsize = js_DenseArrayCapacity(obj);
         if (oldsize >= newlen && !ResizeSlots(cx, obj, oldsize, newlen))
             return JS_FALSE;
     } else if (oldlen - newlen < (1 << 24)) {
         do {
             --oldlen;
             if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                 !DeleteArrayElement(cx, obj, oldlen)) {
                 return JS_FALSE;
@@ -635,23 +631,23 @@ array_lookupProperty(JSContext *cx, JSOb
 {
     uint32 i;
     union { JSProperty *p; jsval *v; } u;
 
     if (!OBJ_IS_DENSE_ARRAY(cx, obj))
         return js_LookupProperty(cx, obj, id, objp, propp);
 
     /*
-     * We have only indexed properties up to DENSELEN (excepting holes), plus
+     * We have only indexed properties up to capacity (excepting holes), plus
      * the length property. For all else, we delegate to the prototype.
      */
     if (id != ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) &&
         (!js_IdIsIndex(id, &i) ||
          obj->fslots[JSSLOT_ARRAY_LENGTH] == 0 ||
-         i >= ARRAY_DENSE_LENGTH(obj) ||
+         i >= js_DenseArrayCapacity(obj) ||
          obj->dslots[i] == JSVAL_HOLE))
     {
         JSObject *proto = STOBJ_GET_PROTO(obj);
 
         if (!proto) {
             *objp = NULL;
             *propp = NULL;
             return JS_TRUE;
@@ -692,17 +688,17 @@ array_getProperty(JSContext *cx, JSObjec
     if (id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) {
         *vp = STOBJ_GET_SLOT(obj, JSSLOT_PROTO);
         return JS_TRUE;
     }
 
     if (!OBJ_IS_DENSE_ARRAY(cx, obj))
         return js_GetProperty(cx, obj, id, vp);
 
-    if (!js_IdIsIndex(ID_TO_VALUE(id), &i) || i >= ARRAY_DENSE_LENGTH(obj) ||
+    if (!js_IdIsIndex(ID_TO_VALUE(id), &i) || i >= js_DenseArrayCapacity(obj) ||
         obj->dslots[i] == JSVAL_HOLE) {
         JSObject *obj2;
         JSProperty *prop;
         JSScopeProperty *sprop;
 
         JSObject *proto = STOBJ_GET_PROTO(obj);
         if (!proto) {
             *vp = JSVAL_VOID;
@@ -778,17 +774,17 @@ array_setProperty(JSContext *cx, JSObjec
         return js_SetProperty(cx, obj, id, vp);
 
     if (!js_IdIsIndex(id, &i) || INDEX_TOO_SPARSE(obj, i)) {
         if (!js_MakeArraySlow(cx, obj))
             return JS_FALSE;
         return js_SetProperty(cx, obj, id, vp);
     }
 
-    if (!EnsureLength(cx, obj, i + 1))
+    if (!EnsureCapacity(cx, obj, i + 1))
         return JS_FALSE;
 
     if (i >= (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH])
         obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
     if (obj->dslots[i] == JSVAL_HOLE)
         obj->fslots[JSSLOT_ARRAY_COUNT]++;
     obj->dslots[i] = *vp;
     return JS_TRUE;
@@ -796,18 +792,18 @@ array_setProperty(JSContext *cx, JSObjec
 
 #ifdef JS_TRACER
 JSBool FASTCALL
 js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, jsval v)
 {
     JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj));
 
     do {
-        jsuint length = ARRAY_DENSE_LENGTH(obj);
-        if ((jsuint)i < length) {
+        jsuint capacity = js_DenseArrayCapacity(obj);
+        if ((jsuint)i < capacity) {
             if (obj->dslots[i] == JSVAL_HOLE) {
                 if (cx->runtime->anyArrayProtoHasElement)
                     break;
                 if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH])
                     obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
                 obj->fslots[JSSLOT_ARRAY_COUNT]++;
             }
             obj->dslots[i] = v;
@@ -865,17 +861,17 @@ array_deleteProperty(JSContext *cx, JSOb
     if (!OBJ_IS_DENSE_ARRAY(cx, obj))
         return js_DeleteProperty(cx, obj, id, rval);
 
     if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
         *rval = JSVAL_FALSE;
         return JS_TRUE;
     }
 
-    if (js_IdIsIndex(id, &i) && i < ARRAY_DENSE_LENGTH(obj) &&
+    if (js_IdIsIndex(id, &i) && i < js_DenseArrayCapacity(obj) &&
         obj->dslots[i] != JSVAL_HOLE) {
         obj->fslots[JSSLOT_ARRAY_COUNT]--;
         obj->dslots[i] = JSVAL_HOLE;
     }
 
     *rval = JSVAL_TRUE;
     return JS_TRUE;
 }
@@ -940,64 +936,64 @@ typedef struct JSIndexIterState {
 #define INDEX_ITER_TAG      3
 
 JS_STATIC_ASSERT(JSVAL_INT == 1);
 
 static JSBool
 array_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                 jsval *statep, jsid *idp)
 {
-    uint32 length, i;
+    uint32 capacity, i;
     JSIndexIterState *ii;
 
     switch (enum_op) {
       case JSENUMERATE_INIT:
         JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj));
-        length = ARRAY_DENSE_LENGTH(obj);
+        capacity = js_DenseArrayCapacity(obj);
         if (idp)
             *idp = INT_TO_JSVAL(obj->fslots[JSSLOT_ARRAY_COUNT]);
         ii = NULL;
-        for (i = 0; i != length; ++i) {
+        for (i = 0; i != capacity; ++i) {
             if (obj->dslots[i] == JSVAL_HOLE) {
                 if (!ii) {
                     ii = (JSIndexIterState *)
                          JS_malloc(cx, offsetof(JSIndexIterState, holes) +
-                                   JS_BITMAP_SIZE(length));
+                                   JS_BITMAP_SIZE(capacity));
                     if (!ii)
                         return JS_FALSE;
                     ii->hasHoles = JS_TRUE;
-                    memset(ii->holes, 0, JS_BITMAP_SIZE(length));
+                    memset(ii->holes, 0, JS_BITMAP_SIZE(capacity));
                 }
                 JS_SET_BIT(ii->holes, i);
             }
         }
         if (!ii) {
             /* Array has no holes. */
-            if (length <= PACKED_UINT_PAIR_MASK) {
-                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(0, length);
+            if (capacity <= PACKED_UINT_PAIR_MASK) {
+                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(0, capacity);
                 break;
             }
             ii = (JSIndexIterState *)
                  JS_malloc(cx, offsetof(JSIndexIterState, holes));
             if (!ii)
                 return JS_FALSE;
             ii->hasHoles = JS_FALSE;
         }
         ii->index = 0;
-        ii->length = length;
+        ii->length = capacity;
         *statep = (jsval) ii | INDEX_ITER_TAG;
         JS_ASSERT(*statep & JSVAL_INT);
         break;
 
       case JSENUMERATE_NEXT:
         if (JSVAL_TAG(*statep) == JSVAL_BOOLEAN) {
-            BOOLEAN_JSVAL_TO_UINT_PAIR(*statep, i, length);
-            if (i != length) {
+            BOOLEAN_JSVAL_TO_UINT_PAIR(*statep, i, capacity);
+            if (i != capacity) {
                 *idp = INT_TO_JSID(i);
-                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(i + 1, length);
+                *statep = UINT_PAIR_TO_BOOLEAN_JSVAL(i + 1, capacity);
                 break;
             }
         } else {
             JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG);
             ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG);
             i = ii->index;
             if (i != ii->length) {
                 /* Skip holes if any. */
@@ -1050,24 +1046,24 @@ array_finalize(JSContext *cx, JSObject *
     if (obj->dslots)
         JS_free(cx, obj->dslots - 1);
     obj->dslots = NULL;
 }
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
-    uint32 length;
+    uint32 capacity;
     size_t i;
     jsval v;
 
     JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj));
 
-    length = ARRAY_DENSE_LENGTH(obj);
-    for (i = 0; i < length; i++) {
+    capacity = js_DenseArrayCapacity(obj);
+    for (i = 0; i < capacity; i++) {
         v = obj->dslots[i];
         if (JSVAL_IS_TRACEABLE(v)) {
             JS_SET_TRACING_INDEX(trc, "array_dslots", i);
             JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
         }
     }
 
     for (i = JSSLOT_PROTO; i <= JSSLOT_PARENT; ++i) {
@@ -1148,36 +1144,36 @@ JSClass js_SlowArrayClass = {
 
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
 JSBool
 js_MakeArraySlow(JSContext *cx, JSObject *obj)
 {
     JSObjectMap *map, *oldmap;
-    uint32 i, length;
+    uint32 i, capacity;
 
     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
 
     /* Create a native scope. */
     map = js_NewObjectMap(cx, obj->map->nrefs, &js_SlowArrayObjectOps,
                           &js_SlowArrayClass, obj);
     if (!map)
         return JS_FALSE;
 
-    length = ARRAY_DENSE_LENGTH(obj);
-    if (length) {
+    capacity = js_DenseArrayCapacity(obj);
+    if (capacity) {
         map->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS;
-        obj->dslots[-1] = JS_INITIAL_NSLOTS + length;
+        obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity;
     } else {
         map->freeslot = STOBJ_NSLOTS(obj);
     }
 
     /* Create new properties pointing to existing values in dslots */
-    for (i = 0; i < length; i++) {
+    for (i = 0; i < capacity; i++) {
         jsid id;
         JSScopeProperty *sprop;
 
         if (!JS_ValueToId(cx, INT_TO_JSVAL(i), &id))
             goto out_bad;
 
         if (obj->dslots[i] == JSVAL_HOLE) {
             obj->dslots[i] = JSVAL_VOID;
@@ -1192,17 +1188,17 @@ js_MakeArraySlow(JSContext *cx, JSObject
     }
 
     /*
      * Render our formerly-reserved count property GC-safe. If length fits in
      * a jsval, set our slow/sparse COUNT to the current length as a jsval, so
      * we can tell when only named properties have been added to a dense array
      * to make it slow-but-not-sparse.
      */
-    length = obj->fslots[JSSLOT_ARRAY_LENGTH];
+    uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
     obj->fslots[JSSLOT_ARRAY_COUNT] = INT_FITS_IN_JSVAL(length)
                                       ? INT_TO_JSVAL(length)
                                       : JSVAL_VOID;
 
     /* Make sure we preserve any flags borrowing bits in classword. */
     obj->classword ^= (jsuword) &js_ArrayClass;
     obj->classword |= (jsuword) &js_SlowArrayClass;
 
@@ -1483,17 +1479,17 @@ array_toLocaleString(JSContext *cx, uint
     return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp);
 }
 
 static JSBool
 InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint end,
                   jsval *vector)
 {
     if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
-        if (!EnsureLength(cx, obj, end))
+        if (!EnsureCapacity(cx, obj, end))
             return JS_FALSE;
 
         if (end > (uint32)obj->fslots[JSSLOT_ARRAY_LENGTH])
             obj->fslots[JSSLOT_ARRAY_LENGTH] = end;
 
         memcpy(obj->dslots + start, vector, sizeof(jsval) * (end - start));
         return JS_TRUE;
     }
@@ -1511,17 +1507,17 @@ static JSBool
 InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector,
                 JSBool holey = JS_FALSE)
 {
     JS_ASSERT(OBJ_IS_ARRAY(cx, obj));
 
     obj->fslots[JSSLOT_ARRAY_LENGTH] = length;
 
     if (vector) {
-        if (!EnsureLength(cx, obj, length))
+        if (!EnsureCapacity(cx, obj, length))
             return JS_FALSE;
 
         jsuint count = length;
         if (!holey) {
             memcpy(obj->dslots, vector, length * sizeof (jsval));
         } else {
             for (jsuint i = 0; i < length; i++) {
                 if (vector[i] == JSVAL_HOLE)
@@ -2121,34 +2117,34 @@ array_push1_dense(JSContext* cx, JSObjec
 {
     uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
     if (INDEX_TOO_SPARSE(obj, length)) {
         if (!js_MakeArraySlow(cx, obj))
             return JS_FALSE;
         return array_push_slowly(cx, obj, 1, &v, rval);
     }
 
-    if (!EnsureLength(cx, obj, length + 1))
+    if (!EnsureCapacity(cx, obj, length + 1))
         return JS_FALSE;
     obj->fslots[JSSLOT_ARRAY_LENGTH] = length + 1;
 
     JS_ASSERT(obj->dslots[length] == JSVAL_HOLE);
     obj->fslots[JSSLOT_ARRAY_COUNT]++;
     obj->dslots[length] = v;
     return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], rval);
 }
 
 JSBool JS_FASTCALL
 js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v)
 {
     JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj));
     uint32_t length = (uint32_t) obj->fslots[JSSLOT_ARRAY_LENGTH];
-    JS_ASSERT(length <= ARRAY_DENSE_LENGTH(obj));
-
-    if (length == ARRAY_DENSE_LENGTH(obj)) {
+    JS_ASSERT(length <= js_DenseArrayCapacity(obj));
+
+    if (length == js_DenseArrayCapacity(obj)) {
         if (length >= ARRAY_INIT_LIMIT) {
             JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
                                    JSMSG_ARRAY_INIT_TOO_BIG);
             return JS_FALSE;
         }
 
         if (!ResizeSlots(cx, obj, length, length + ARRAY_GROWBY))
             return JS_FALSE;
@@ -2492,25 +2488,25 @@ array_concat(JSContext *cx, uintN argc, 
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
     argv = JS_ARGV(cx, vp) - 1;
     JS_ASSERT(JS_THIS_OBJECT(cx, vp) == JSVAL_TO_OBJECT(argv[0]));
 
     /* Create a new Array object and root it using *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 (aka
-         * "dense length"), 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 dense length.
+         * 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.
          */
         length = aobj->fslots[JSSLOT_ARRAY_LENGTH];
-        jsuint capacity = ARRAY_DENSE_LENGTH(aobj);
+        jsuint capacity = js_DenseArrayCapacity(aobj);
         nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->dslots,
                                  aobj->fslots[JSSLOT_ARRAY_COUNT] !=
                                  (jsval) length);
         if (!nobj)
             return JS_FALSE;
         nobj->fslots[JSSLOT_ARRAY_LENGTH] = length;
         *vp = OBJECT_TO_JSVAL(nobj);
         if (argc == 0)
@@ -2632,17 +2628,17 @@ array_slice(JSContext *cx, uintN argc, j
             }
             end = (jsuint)d;
         }
     }
 
     if (begin > end)
         begin = end;
 
-    if (OBJ_IS_DENSE_ARRAY(cx, obj) && end <= ARRAY_DENSE_LENGTH(obj)) {
+    if (OBJ_IS_DENSE_ARRAY(cx, obj) && end <= js_DenseArrayCapacity(obj)) {
         nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin,
                                  obj->fslots[JSSLOT_ARRAY_COUNT] !=
                                  obj->fslots[JSSLOT_ARRAY_LENGTH]);
         if (!nobj)
             return JS_FALSE;
         *vp = OBJECT_TO_JSVAL(nobj);
         return JS_TRUE;
     }
@@ -3136,17 +3132,17 @@ js_NewUninitializedArray(JSContext* cx, 
 #define ARRAY_CTOR_GUTS(exact_len, newslots_code)                             \
     JS_ASSERT(JS_ON_TRACE(cx));                                               \
     JSObject* obj = js_FastNewArray(cx, proto);                               \
     if (obj) {                                                                \
         const uint32 len = ARRAY_GROWBY;                                      \
         jsval* newslots = (jsval*) JS_malloc(cx, sizeof (jsval) * (len + 1)); \
         if (newslots) {                                                       \
             obj->dslots = newslots + 1;                                       \
-            ARRAY_SET_DENSE_LENGTH(obj, len);                                 \
+            js_SetDenseArrayCapacity(obj, len);                               \
             {newslots_code}                                                   \
             while (++newslots < obj->dslots + len)                            \
                 *newslots = JSVAL_HOLE;                                       \
             obj->fslots[JSSLOT_ARRAY_LENGTH] = (exact_len);                   \
             return obj;                                                       \
         }                                                                     \
     }                                                                         \
     return NULL;
@@ -3227,19 +3223,19 @@ js_ArrayInfo(JSContext *cx, JSObject *ob
             fprintf(stderr, "%s: not array\n", bytes);
             JS_free(cx, bytes);
             continue;
         }
         fprintf(stderr, "%s: %s (len %lu", bytes,
                 OBJ_IS_DENSE_ARRAY(cx, array) ? "dense" : "sparse",
                 array->fslots[JSSLOT_ARRAY_LENGTH]);
         if (OBJ_IS_DENSE_ARRAY(cx, array)) {
-            fprintf(stderr, ", count %lu, denselen %lu",
+            fprintf(stderr, ", count %lu, capacity %lu",
                     array->fslots[JSSLOT_ARRAY_COUNT],
-                    ARRAY_DENSE_LENGTH(array));
+                    js_DenseArrayCapacity(array));
         }
         fputs(")\n", stderr);
         JS_free(cx, bytes);
     }
     return JS_TRUE;
 }
 #endif
 
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -39,16 +39,17 @@
 
 #ifndef jsarray_h___
 #define jsarray_h___
 /*
  * JS Array interface.
  */
 #include "jsprvtd.h"
 #include "jspubtd.h"
+#include "jsobj.h"
 
 JS_BEGIN_EXTERN_C
 
 /* Generous sanity-bound on length (in elements) of array initialiser. */
 #define ARRAY_INIT_LIMIT        JS_BIT(24)
 
 extern JSBool
 js_IdIsIndex(jsval id, jsuint *indexp);
@@ -73,22 +74,30 @@ js_NewSlowArrayObject(JSContext *cx);
 
 extern JSBool
 js_MakeArraySlow(JSContext *cx, JSObject *obj);
 
 #define JSSLOT_ARRAY_LENGTH            JSSLOT_PRIVATE
 #define JSSLOT_ARRAY_COUNT             (JSSLOT_ARRAY_LENGTH + 1)
 #define JSSLOT_ARRAY_LOOKUP_HOLDER     (JSSLOT_ARRAY_COUNT + 1)
 
-#define ARRAY_DENSE_LENGTH(obj)                                                \
-    (JS_ASSERT(OBJ_IS_DENSE_ARRAY(cx, obj)),                                   \
-     (obj)->dslots ? (uint32)(obj)->dslots[-1] : 0)
+static JS_INLINE uint32
+js_DenseArrayCapacity(JSObject *obj)
+{
+    JS_ASSERT(OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj));
+    return obj->dslots ? (uint32) obj->dslots[-1] : 0;
+}
 
-#define ARRAY_SET_DENSE_LENGTH(obj, max)                                       \
-    (JS_ASSERT((obj)->dslots), (obj)->dslots[-1] = (jsval)(max))
+static JS_INLINE void
+js_SetDenseArrayCapacity(JSObject *obj, uint32 capacity)
+{
+    JS_ASSERT(OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj));
+    JS_ASSERT(obj->dslots);
+    obj->dslots[-1] = (jsval) capacity;
+}
 
 #define ARRAY_GROWBY 8
 
 extern JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
 
 extern JSBool
 js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4666,17 +4666,17 @@ js_Interpret(JSContext *cx)
                 }
             }
 
             VALUE_TO_OBJECT(cx, -2, lval, obj);
             if (JSVAL_IS_INT(rval)) {
                 if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
                     jsuint length;
 
-                    length = ARRAY_DENSE_LENGTH(obj);
+                    length = js_DenseArrayCapacity(obj);
                     i = JSVAL_TO_INT(rval);
                     if ((jsuint)i < length &&
                         i < obj->fslots[JSSLOT_ARRAY_LENGTH]) {
                         rval = obj->dslots[i];
                         if (rval != JSVAL_HOLE)
                             goto end_getelem;
 
                         /* Reload rval from the stack in the rare hole case. */
@@ -4719,17 +4719,17 @@ js_Interpret(JSContext *cx)
           BEGIN_CASE(JSOP_SETELEM)
             rval = FETCH_OPND(-1);
             FETCH_OBJECT(cx, -3, lval, obj);
             FETCH_ELEMENT_ID(obj, -2, id);
             do {
                 if (OBJ_IS_DENSE_ARRAY(cx, obj) && JSID_IS_INT(id)) {
                     jsuint length;
 
-                    length = ARRAY_DENSE_LENGTH(obj);
+                    length = js_DenseArrayCapacity(obj);
                     i = JSID_TO_INT(id);
                     if ((jsuint)i < length) {
                         if (obj->dslots[i] == JSVAL_HOLE) {
                             if (rt->anyArrayProtoHasElement)
                                 break;
                             if (i >= obj->fslots[JSSLOT_ARRAY_LENGTH])
                                 obj->fslots[JSSLOT_ARRAY_LENGTH] = i + 1;
                             obj->fslots[JSSLOT_ARRAY_COUNT]++;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -5738,17 +5738,17 @@ js_DumpObject(JSObject *obj)
 
     fprintf(stderr, "object %p\n", (void *) obj);
     clasp = STOBJ_GET_CLASS(obj);
     fprintf(stderr, "class %p %s\n", (void *)clasp, clasp->name);
 
     /* OBJ_IS_DENSE_ARRAY ignores the cx argument. */
     if (OBJ_IS_DENSE_ARRAY(BOGUS_CX, obj)) {
         slots = JS_MIN((jsuint) obj->fslots[JSSLOT_ARRAY_LENGTH],
-                       ARRAY_DENSE_LENGTH(obj));
+                       js_DenseArrayCapacity(obj));
         fprintf(stderr, "elements\n");
         for (i = 0; i < slots; i++) {
             fprintf(stderr, " %3d: ", i);
             dumpValue(obj->dslots[i]);
             fprintf(stderr, "\n");
             fflush(stderr);
         }
         return;
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -5924,19 +5924,19 @@ TraceRecorder::guardDenseArray(JSObject*
 {
     return guardClass(obj, obj_ins, &js_ArrayClass, exitType);
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::guardDenseArrayIndex(JSObject* obj, jsint idx, LIns* obj_ins,
                                     LIns* dslots_ins, LIns* idx_ins, ExitType exitType)
 {
-    jsuint length = ARRAY_DENSE_LENGTH(obj);
-
-    bool cond = (jsuint(idx) < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && jsuint(idx) < length);
+    jsuint capacity = js_DenseArrayCapacity(obj);
+
+    bool cond = (jsuint(idx) < jsuint(obj->fslots[JSSLOT_ARRAY_LENGTH]) && jsuint(idx) < capacity);
     if (cond) {
         /* Guard array length */
         LIns* exit = guard(true,
                            lir->ins2(LIR_ult, idx_ins, stobj_get_fslot(obj_ins, JSSLOT_ARRAY_LENGTH)),
                            exitType)->oprnd2();
         /* dslots must not be NULL */
         guard(false,
               lir->ins_eq0(dslots_ins),
@@ -7151,17 +7151,17 @@ TraceRecorder::record_JSOP_GETELEM()
     /* Property access using a string name. */
     if (JSVAL_IS_STRING(idx)) {
         if (!js_ValueToStringId(cx, idx, &id))
             return false;
         // Store the interned string to the stack to save the interpreter from redoing this work.
         idx = ID_TO_VALUE(id);
         jsuint index;
         if (js_IdIsIndex(idx, &index) && guardDenseArray(obj, obj_ins, BRANCH_EXIT)) {
-            v = (index >= ARRAY_DENSE_LENGTH(obj)) ? JSVAL_HOLE : obj->dslots[index];
+            v = (index >= js_DenseArrayCapacity(obj)) ? JSVAL_HOLE : obj->dslots[index];
             if (v == JSVAL_HOLE)
                 ABORT_TRACE("can't see through hole in dense array");
         } else {
             if (!guardElemOp(obj, obj_ins, id, offsetof(JSObjectOps, getProperty), &v))
                 return false;
         }
         return call_imacro(getelem_imacros.getprop);
     }