Maintain a list of IdArrays as we hand them out via JS API (638324, r=brendan).
☠☠ backed out by 823d4b7517c2 ☠ ☠
authorAndreas Gal <gal@mozilla.com>
Thu, 31 Mar 2011 14:42:33 -0700
changeset 67896 bd821ea0ad41b971740e687206c1ed4305b401e0
parent 67895 c46b4248ee360d41045a113d0eef566624f61d56
child 67897 0477bca4863dc17bc065065957c2c8d4dd39b0b8
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs638324
milestone2.2a1pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Maintain a list of IdArrays as we hand them out via JS API (638324, r=brendan).
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1889,140 +1889,16 @@ JS_EnumerateStandardClasses(JSContext *c
             !standard_class_atoms[i].init(cx, obj)) {
             return JS_FALSE;
         }
     }
 
     return JS_TRUE;
 }
 
-namespace js {
-
-JSIdArray *
-NewIdArray(JSContext *cx, jsint length)
-{
-    JSIdArray *ida;
-
-    ida = (JSIdArray *)
-        cx->calloc_(offsetof(JSIdArray, vector) + length * sizeof(jsval));
-    if (ida)
-        ida->length = length;
-    return ida;
-}
-
-}
-
-/*
- * Unlike realloc(3), this function frees ida on failure.
- */
-static JSIdArray *
-SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
-{
-    JSIdArray *rida;
-
-    rida = (JSIdArray *)
-           JS_realloc(cx, ida,
-                      offsetof(JSIdArray, vector) + length * sizeof(jsval));
-    if (!rida) {
-        JS_DestroyIdArray(cx, ida);
-    } else {
-        rida->length = length;
-    }
-    return rida;
-}
-
-static JSIdArray *
-AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
-{
-    jsint i, length;
-
-    i = *ip;
-    length = ida->length;
-    if (i >= length) {
-        ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
-        if (!ida)
-            return NULL;
-        JS_ASSERT(i < ida->length);
-    }
-    ida->vector[i] = ATOM_TO_JSID(atom);
-    *ip = i + 1;
-    return ida;
-}
-
-static JSIdArray *
-EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
-                    jsint *ip, JSBool *foundp)
-{
-    *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
-    if (*foundp)
-        ida = AddAtomToArray(cx, atom, ida, ip);
-    return ida;
-}
-
-JS_PUBLIC_API(JSIdArray *)
-JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
-{
-    JSRuntime *rt;
-    jsint i, j, k;
-    JSAtom *atom;
-    JSBool found;
-    JSObjectOp init;
-
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, ida);
-    rt = cx->runtime;
-    if (ida) {
-        i = ida->length;
-    } else {
-        ida = NewIdArray(cx, 8);
-        if (!ida)
-            return NULL;
-        i = 0;
-    }
-
-    /* Check whether 'undefined' has been resolved and enumerate it if so. */
-    atom = rt->atomState.typeAtoms[JSTYPE_VOID];
-    ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
-    if (!ida)
-        return NULL;
-
-    /* Enumerate only classes that *have* been resolved. */
-    for (j = 0; standard_class_atoms[j].init; j++) {
-        atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
-        ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
-        if (!ida)
-            return NULL;
-
-        if (found) {
-            init = standard_class_atoms[j].init;
-
-            for (k = 0; standard_class_names[k].init; k++) {
-                if (standard_class_names[k].init == init) {
-                    atom = StdNameToAtom(cx, &standard_class_names[k]);
-                    ida = AddAtomToArray(cx, atom, ida, &i);
-                    if (!ida)
-                        return NULL;
-                }
-            }
-
-            if (init == js_InitObjectClass) {
-                for (k = 0; object_prototype_names[k].init; k++) {
-                    atom = StdNameToAtom(cx, &object_prototype_names[k]);
-                    ida = AddAtomToArray(cx, atom, ida, &i);
-                    if (!ida)
-                        return NULL;
-                }
-            }
-        }
-    }
-
-    /* Trim to exact length. */
-    return SetIdArrayLength(cx, ida, i);
-}
-
 #undef CLASP
 #undef EAGER_ATOM
 #undef EAGER_CLASS_ATOM
 #undef EAGER_ATOM_CLASP
 #undef LAZY_ATOM
 
 JS_PUBLIC_API(JSBool)
 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
@@ -2838,22 +2714,16 @@ JS_SetNativeStackQuota(JSContext *cx, si
 JS_PUBLIC_API(void)
 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
 {
     cx->scriptStackQuota = quota;
 }
 
 /************************************************************************/
 
-JS_PUBLIC_API(void)
-JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
-{
-    cx->free_(ida);
-}
-
 JS_PUBLIC_API(JSBool)
 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return ValueToId(cx, Valueify(v), idp);
 }
 
@@ -3963,31 +3833,66 @@ JS_ClearScope(JSContext *cx, JSObject *o
         int32 flags = obj->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32();
         flags |= JSGLOBAL_FLAGS_CLEARED;
         JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Jsvalify(Int32Value(flags)));
     }
 
     js_InitRandom(cx);
 }
 
+static bool
+RegisterIdArray(JSContext *cx, JSIdArray *ida)
+{
+    return JS_THREAD_DATA(cx)->idArraysHandedOutViaAPI.append(ida);
+}
+
+static void
+UnregisterIdArray(JSContext *cx, JSIdArray *ida)
+{
+    js::Vector<JSIdArray *, 4, SystemAllocPolicy> &idArrays = JS_THREAD_DATA(cx)->idArraysHandedOutViaAPI;
+    for (size_t n = 0; n < idArrays.length(); ++n) {
+        if (idArrays[n] == ida) {
+            idArrays.erase(&idArrays[n]);
+            return;
+        }
+    }
+}
+
+static void
+DestroyIdArray(JSContext *cx, JSIdArray *ida)
+{
+    cx->free_(ida);
+}
+
 JS_PUBLIC_API(JSIdArray *)
 JS_Enumerate(JSContext *cx, JSObject *obj)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     AutoIdVector props(cx);
     JSIdArray *ida;
     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
         return false;
+    if (!RegisterIdArray(cx, ida)) {
+        DestroyIdArray(cx, ida);
+        return NULL;
+    }
     for (size_t n = 0; n < size_t(ida->length); ++n)
         JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
     return ida;
 }
 
+JS_PUBLIC_API(void)
+JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
+{
+    UnregisterIdArray(cx, ida);
+    DestroyIdArray(cx, ida);
+}
+
 /*
  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
  *     prop_iterator_class somehow...
  * + preserve the obj->enumerate API while optimizing the native object case
  * + native case here uses a Shape *, but that iterates in reverse!
  * + so we make non-native match, by reverse-iterating after JS_Enumerating
  */
 const uint32 JSSLOT_ITER_INDEX = 0;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -506,21 +506,16 @@ AllFramesIter::operator++()
         curfp = curfp->prev();
     }
     return *this;
 }
 
 bool
 JSThreadData::init()
 {
-#ifdef DEBUG
-    /* The data must be already zeroed. */
-    for (size_t i = 0; i != sizeof(*this); ++i)
-        JS_ASSERT(reinterpret_cast<uint8*>(this)[i] == 0);
-#endif
     if (!stackSpace.init())
         return false;
     dtoaState = js_NewDtoaState();
     if (!dtoaState) {
         finish();
         return false;
     }
     nativeStackBase = GetNativeStackBase();
@@ -543,16 +538,21 @@ JSThreadData::finish()
     propertyCache.~PropertyCache();
     stackSpace.finish();
 }
 
 void
 JSThreadData::mark(JSTracer *trc)
 {
     stackSpace.mark(trc);
+
+    for (size_t n = 0; n < idArraysHandedOutViaAPI.length(); ++n) {
+        JSIdArray *ida = idArraysHandedOutViaAPI[n];
+        gc::MarkIdRange(trc, ida->length, ida->vector, "JSThreadData::idArraysHandedOutViaAPI");
+    }
 }
 
 void
 JSThreadData::purge(JSContext *cx)
 {
     js_PurgeGSNCache(&gsnCache);
 
     /* FIXME: bug 506341. */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -890,16 +890,19 @@ struct JSThreadData {
     DtoaState           *dtoaState;
 
     /* Base address of the native stack for the current thread. */
     jsuword             *nativeStackBase;
 
     /* List of currently pending operations on proxies. */
     JSPendingProxyOperation *pendingProxyOperation;
 
+    /* List of id arrays in use. */
+    js::Vector<JSIdArray *, 4, js::SystemAllocPolicy> idArraysHandedOutViaAPI;
+
     js::ConservativeGCThreadData conservativeGC;
 
     bool init();
     void finish();
     void mark(JSTracer *trc);
     void purge(JSContext *cx);
 
     /* This must be called with the GC lock held. */
@@ -3284,19 +3287,16 @@ class AutoShapeVector : public AutoVecto
         : AutoVectorRooter<const Shape *>(cx, SHAPEVECTOR)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-JSIdArray *
-NewIdArray(JSContext *cx, jsint length);
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
 #endif /* jscntxt_h___ */