Remove gcIteratorTable (557914, r=brendan).
authorAndreas Gal <gal@mozilla.com>
Sat, 10 Apr 2010 16:08:14 -0700
changeset 40857 121debb9ff3d7362f3bd8be330144420f7f86d53
parent 40856 7bdf4c4951896a47152974fdc37203c28f07aff5
child 40858 fe0495fbde4c5443d795f6874878ccbd710ca802
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
bugs557914
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Remove gcIteratorTable (557914, r=brendan).
js/src/jscntxt.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsobj.cpp
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -797,22 +797,16 @@ struct JSRuntime {
 
     /* See comments before DelayMarkingChildren is jsgc.cpp. */
     JSGCArena           *gcUnmarkedArenaStackTop;
 #ifdef DEBUG
     size_t              gcMarkLaterCount;
 #endif
 
     /*
-     * Table for tracking iterators to ensure that we close iterator's state
-     * before finalizing the iterable object.
-     */
-    js::Vector<JSObject*, 0, js::SystemAllocPolicy> gcIteratorTable;
-
-    /*
      * The trace operation and its data argument to trace embedding-specific
      * GC roots.
      */
     JSTraceDataOp       gcExtraRootsTraceOp;
     void                *gcExtraRootsData;
 
     /*
      * Used to serialize cycle checks when setting __proto__ or __parent__ by
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -758,16 +758,17 @@ DestroyGCArenas(JSRuntime *rt, JSGCArena
 
 static inline size_t
 GetFinalizableThingSize(unsigned thingKind)
 {
     JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
 
     static const uint8 map[FINALIZE_LIMIT] = {
         sizeof(JSObject),   /* FINALIZE_OBJECT */
+        sizeof(JSObject),   /* FINALIZE_ITER */
         sizeof(JSFunction), /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT
         sizeof(JSXML),      /* FINALIZE_XML */
 #endif
         sizeof(JSString),   /* FINALIZE_STRING */
         sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING0 */
         sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING1 */
         sizeof(JSString),   /* FINALIZE_EXTERNAL_STRING2 */
@@ -784,16 +785,17 @@ GetFinalizableThingSize(unsigned thingKi
 
 static inline size_t
 GetFinalizableTraceKind(size_t thingKind)
 {
     JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
 
     static const uint8 map[FINALIZE_LIMIT] = {
         JSTRACE_OBJECT,     /* FINALIZE_OBJECT */
+        JSTRACE_OBJECT,     /* FINALIZE_ITER */
         JSTRACE_OBJECT,     /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT      /* FINALIZE_XML */
         JSTRACE_XML,
 #endif                      /* FINALIZE_STRING */
         JSTRACE_STRING,
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING0 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING1 */
         JSTRACE_STRING,     /* FINALIZE_EXTERNAL_STRING2 */
@@ -986,16 +988,17 @@ UpdateArenaStats(JSGCArenaStats *st, uin
 }
 
 JS_FRIEND_API(void)
 js_DumpGCStats(JSRuntime *rt, FILE *fp)
 {
     static const char *const GC_ARENA_NAMES[] = {
         "double",
         "object",
+        "iter",
         "function",
 #if JS_HAS_XML_SUPPORT
         "xml",
 #endif
         "string",
         "external_string_0",
         "external_string_1",
         "external_string_2",
@@ -1144,17 +1147,16 @@ js_FinishGC(JSRuntime *rt)
 #ifdef JS_ARENAMETER
     JS_DumpArenaStats(stdout);
 #endif
 #ifdef JS_GCMETER
     if (JS_WANT_GC_METER_PRINT)
         js_DumpGCStats(rt, stdout);
 #endif
 
-    rt->gcIteratorTable.clear();
     FinishGCArenaLists(rt);
 
     if (rt->gcRootsHash.ops) {
 #ifdef DEBUG
         CheckLeakedRoots(rt);
 #endif
         JS_DHashTableFinish(&rt->gcRootsHash);
         rt->gcRootsHash.ops = NULL;
@@ -1323,44 +1325,16 @@ js_gcroot_mapper(JSDHashTable *table, JS
 uint32
 js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
 {
     GCRootMapArgs args = {map, data};
     AutoLockGC lock(rt);
     return JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
 }
 
-JSBool
-js_RegisterCloseableIterator(JSContext *cx, JSObject *obj)
-{
-    JSRuntime *rt = cx->runtime;
-    JS_ASSERT(!rt->gcRunning);
-
-    AutoLockGC lock(rt);
-    return rt->gcIteratorTable.append(obj);
-}
-
-static void
-CloseNativeIterators(JSContext *cx)
-{
-    JSRuntime *rt = cx->runtime;
-    size_t length = rt->gcIteratorTable.length();
-    JSObject **array = rt->gcIteratorTable.begin();
-
-    size_t newLength = 0;
-    for (size_t i = 0; i < length; ++i) {
-        JSObject *obj = array[i];
-        if (js_IsAboutToBeFinalized(obj))
-            js_CloseNativeIterator(cx, obj);
-        else
-            array[newLength++] = obj;
-    }
-    rt->gcIteratorTable.resize(newLength);
-}
-
 void
 JSRuntime::setGCTriggerFactor(uint32 factor)
 {
     JS_ASSERT(factor >= 100);
 
     gcTriggerFactor = factor;
     setGCLastBytes(gcLastBytes);
 }
@@ -2318,16 +2292,17 @@ js_TraceStackFrame(JSTracer *trc, JSStac
 }
 
 void
 JSWeakRoots::mark(JSTracer *trc)
 {
 #ifdef DEBUG
     const char * const newbornNames[] = {
         "newborn_object",             /* FINALIZE_OBJECT */
+        "newborn_iter",               /* FINALIZE_ITER */
         "newborn_function",           /* FINALIZE_FUNCTION */
 #if JS_HAS_XML_SUPPORT
         "newborn_xml",                /* FINALIZE_XML */
 #endif
         "newborn_string",             /* FINALIZE_STRING */
         "newborn_external_string0",   /* FINALIZE_EXTERNAL_STRING0 */
         "newborn_external_string1",   /* FINALIZE_EXTERNAL_STRING1 */
         "newborn_external_string2",   /* FINALIZE_EXTERNAL_STRING2 */
@@ -2517,17 +2492,19 @@ js_DestroyScriptsToGC(JSContext *cx, JST
             js_DestroyScript(cx, script);
         }
     }
 }
 
 inline void
 FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind)
 {
-    JS_ASSERT(thingKind == FINALIZE_FUNCTION || thingKind == FINALIZE_OBJECT);
+    JS_ASSERT(thingKind == FINALIZE_OBJECT ||
+              thingKind == FINALIZE_ITER ||
+              thingKind == FINALIZE_FUNCTION);
 
     /* Cope with stillborn objects that have no map. */
     if (!obj->map)
         return;
 
     /* Finalize obj first, in case it needs map and slots. */
     JSClass *clasp = obj->getClass();
     if (clasp->finalize)
@@ -2967,19 +2944,16 @@ GC(JSContext *cx, JSGCInvocationKind gck
      * entry can be freed. Note that even after the entry is freed, JSObject
      * finalizers can continue to access the corresponding jsdouble* and
      * JSString* assuming that they are unique. This works since the
      * atomization API must not be called during GC.
      */
     TIMESTAMP(gcTimer.startSweep);
     js_SweepAtomState(cx);
 
-    /* Finalize iterator states before the objects they iterate over. */
-    CloseNativeIterators(cx);
-
     /* Finalize watch points associated with unreachable objects. */
     js_SweepWatchPoints(cx);
 
 #ifdef DEBUG
     /* Save the pre-sweep count of scope-mapped properties. */
     rt->liveScopePropsPreSweep = rt->liveScopeProps;
 #endif
 
@@ -2990,21 +2964,25 @@ GC(JSContext *cx, JSGCInvocationKind gck
      *
      * To minimize the number of checks per each to be freed object and
      * function we use separated list finalizers when a debug hook is
      * installed.
      */
     JSGCArena *emptyArenas = NULL;
     if (!cx->debugHooks->objectHook) {
         FinalizeArenaList<JSObject, FinalizeObject>
+            (cx, FINALIZE_ITER, &emptyArenas);
+        FinalizeArenaList<JSObject, FinalizeObject>
             (cx, FINALIZE_OBJECT, &emptyArenas);
         FinalizeArenaList<JSFunction, FinalizeFunction>
             (cx, FINALIZE_FUNCTION, &emptyArenas);
     } else {
         FinalizeArenaList<JSObject, FinalizeHookedObject>
+            (cx, FINALIZE_ITER, &emptyArenas);
+        FinalizeArenaList<JSObject, FinalizeHookedObject>
             (cx, FINALIZE_OBJECT, &emptyArenas);
         FinalizeArenaList<JSFunction, FinalizeHookedFunction>
             (cx, FINALIZE_FUNCTION, &emptyArenas);
     }
 #if JS_HAS_XML_SUPPORT
     FinalizeArenaList<JSXML, FinalizeXML>(cx, FINALIZE_XML, &emptyArenas);
 #endif
     TIMESTAMP(gcTimer.sweepObjectEnd);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -235,16 +235,17 @@ extern void
 js_CallGCMarker(JSTracer *trc, void *thing, uint32 kind);
 
 /*
  * The kind of GC thing with a finalizer. The external strings follow the
  * ordinary string to simplify js_GetExternalStringGCType.
  */
 enum JSFinalizeGCThingKind {
     FINALIZE_OBJECT,
+    FINALIZE_ITER,
     FINALIZE_FUNCTION,
 #if JS_HAS_XML_SUPPORT
     FINALIZE_XML,
 #endif
     FINALIZE_STRING,
     FINALIZE_EXTERNAL_STRING0,
     FINALIZE_EXTERNAL_STRING1,
     FINALIZE_EXTERNAL_STRING2,
@@ -274,16 +275,22 @@ extern void *
 js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind);
 
 static inline JSObject *
 js_NewGCObject(JSContext *cx)
 {
     return (JSObject *) js_NewFinalizableGCThing(cx, FINALIZE_OBJECT);
 }
 
+static inline JSObject *
+js_NewGCIter(JSContext *cx)
+{
+    return (JSObject *) js_NewFinalizableGCThing(cx, FINALIZE_ITER);
+}
+
 static inline JSString *
 js_NewGCString(JSContext *cx)
 {
     return (JSString *) js_NewFinalizableGCThing(cx, FINALIZE_STRING);
 }
 
 static inline JSString *
 js_NewGCExternalString(JSContext *cx, uintN type)
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -82,25 +82,25 @@ static JS_REQUIRES_STACK JSBool
 CloseGenerator(JSContext *cx, JSObject *genobj);
 
 #endif
 
 /*
  * Shared code to close iterator's state either through an explicit call or
  * when GC detects that the iterator is no longer reachable.
  */
-void
-js_CloseNativeIterator(JSContext *cx, JSObject *iterobj)
+static void
+CloseNativeIterator(JSContext *cx, JSObject *iterobj)
 {
     jsval state;
     JSObject *iterable;
 
     JS_ASSERT(iterobj->getClass() == &js_IteratorClass);
 
-    /* Avoid double work if js_CloseNativeIterator was called on obj. */
+    /* Avoid double work if CloseNativeIterator was called on obj. */
     state = iterobj->getSlot(JSSLOT_ITER_STATE);
     if (JSVAL_IS_NULL(state))
         return;
 
     /* Protect against failure to fully initialize obj. */
     iterable = iterobj->getParent();
     if (iterable) {
 #if JS_HAS_XML_SUPPORT
@@ -111,16 +111,22 @@ js_CloseNativeIterator(JSContext *cx, JS
         } else
 #endif
             iterable->enumerate(cx, JSENUMERATE_DESTROY, &state, NULL);
     }
     iterobj->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL);
 }
 
 static void
+iterator_finalize(JSContext *cx, JSObject *obj)
+{
+    CloseNativeIterator(cx, obj);
+}
+
+static void
 iterator_trace(JSTracer *trc, JSObject *obj)
 {
     /*
      * The GC marks iter_state during the normal slot scanning if
      * JSVAL_IS_TRACEABLE(iter_state) is true duplicating the efforts of
      * js_MarkEnumeratorState. But this is rare so we optimize for code
      * simplicity.
      */
@@ -133,36 +139,34 @@ iterator_trace(JSTracer *trc, JSObject *
     js_MarkEnumeratorState(trc, iterable, iter_state);
 }
 
 JSClass js_IteratorClass = {
     "Iterator",
     JSCLASS_HAS_RESERVED_SLOTS(2) | /* slots for state and flags */
     JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
     JSCLASS_MARK_IS_TRACE,
-    JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   NULL,
-    NULL,             NULL,            NULL,            NULL,
+    JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub,  JS_PropertyStub,
+    JS_EnumerateStub, JS_ResolveStub,  JS_ConvertStub,   iterator_finalize,
+    NULL,             NULL,            NULL,             NULL,
     NULL,             NULL,            JS_CLASS_TRACE(iterator_trace), NULL
 };
 
 static JSBool
 InitNativeIterator(JSContext *cx, JSObject *iterobj, JSObject *obj, uintN flags)
 {
     jsval state;
     JSBool ok;
 
     JS_ASSERT(iterobj->getClass() == &js_IteratorClass);
 
     /* Initialize iterobj in case of enumerate hook failure. */
     iterobj->setParent(obj);
     iterobj->setSlot(JSSLOT_ITER_STATE, JSVAL_NULL);
     iterobj->setSlot(JSSLOT_ITER_FLAGS, INT_TO_JSVAL(flags));
-    if (!js_RegisterCloseableIterator(cx, iterobj))
-        return JS_FALSE;
     if (!obj)
         return JS_TRUE;
 
     ok =
 #if JS_HAS_XML_SUPPORT
          ((flags & JSITER_FOREACH) && OBJECT_IS_XML(cx, obj))
          ? js_EnumerateXMLValues(cx, obj, JSENUMERATE_INIT, &state, NULL, NULL)
          :
@@ -442,17 +446,17 @@ js_CloseIterator(JSContext *cx, jsval v)
     JSObject *obj;
     JSClass *clasp;
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
     obj = JSVAL_TO_OBJECT(v);
     clasp = obj->getClass();
 
     if (clasp == &js_IteratorClass) {
-        js_CloseNativeIterator(cx, obj);
+        CloseNativeIterator(cx, obj);
 
         /*
          * Note that we don't care what kind of iterator we close here. Even if it
          * is not JSITER_ENUMERATE, it is safe to re-use the object later on for a
          * JSITER_ENUMERATE iteration.
          */
         JS_THREAD_DATA(cx)->cachedIteratorObject = obj;
     }
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -78,22 +78,16 @@ js_CloseIterator(JSContext *cx, jsval v)
 
 /*
  * Given iterobj, call iterobj.next().  If the iterator stopped, set *rval to
  * JSVAL_HOLE. Otherwise set it to the result of the next call.
  */
 extern JS_FRIEND_API(JSBool)
 js_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval);
 
-/*
- * Close iterobj, whose class must be js_IteratorClass.
- */
-extern void
-js_CloseNativeIterator(JSContext *cx, JSObject *iterobj);
-
 extern JSBool
 js_ThrowStopIteration(JSContext *cx);
 
 #if JS_HAS_GENERATORS
 
 /*
  * Generator state codes.
  */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2792,17 +2792,19 @@ js_NewObjectWithGivenProto(JSContext *cx
 #ifdef DEBUG
         if (obj) {
             memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
                    sizeof(JSFunction) - sizeof(JSObject));
         }
 #endif
     } else {
         JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
-        obj = js_NewGCObject(cx);
+        obj = (clasp == &js_IteratorClass)
+            ? js_NewGCIter(cx)
+            : js_NewGCObject(cx);
     }
     if (!obj)
         goto out;
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */