bug 517199 - typed GC free lsists - newborn refactoring. r=brendan
☠☠ backed out by 0416997adea8 ☠ ☠
authorIgor Bukanov <igor@mir2.org>
Thu, 01 Oct 2009 08:13:04 +0400
changeset 33572 19b4c1cacdb8566e50754fa077448f82f5fdb333
parent 33571 1257326d9db88eb4207c409de6d0e2c8a789cad5
child 33573 47619e6bad9aef45e2687a9617b50c4f78b52ad0
child 33577 0416997adea8dea5e38e9ff5ed802fd1d29857b3
push idunknown
push userunknown
push dateunknown
reviewersbrendan
bugs517199
milestone1.9.3a1pre
bug 517199 - typed GC free lsists - newborn refactoring. r=brendan
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbuiltins.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsobj.cpp
js/src/jsops.cpp
js/src/jsstr.cpp
js/src/jsxml.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2598,22 +2598,20 @@ JS_PUBLIC_API(intN)
 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
 {
     return js_ChangeExternalStringFinalizer(finalizer, NULL);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
 {
-    JSString *str;
-
     CHECK_REQUEST(cx);
-    JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
-
-    str = js_NewGCString(cx, (uintN) type + GCX_EXTERNAL_STRING);
+    JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
+
+    JSString *str = js_NewGCExternalString(cx, uintN(type));
     if (!str)
         return NULL;
     str->initFlat(chars, length);
     cx->updateMallocCounter((length + 1) * sizeof(jschar));
     return str;
 }
 
 JS_PUBLIC_API(intN)
@@ -4864,17 +4862,17 @@ JS_CompileUCFunctionForPrincipals(JSCont
 
         while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
             ++depth;
         JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
     }
 #endif
 
   out:
-    cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun);
+    cx->weakRoots.newbornObject = FUN_OBJECT(fun);
     JS_POP_TEMP_ROOT(cx, &tvr);
 
   out2:
     LAST_FRAME_CHECKS(cx, fun);
     return fun;
 }
 
 JS_PUBLIC_API(JSString *)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3386,17 +3386,17 @@ js_Array(JSContext *cx, JSObject *obj, u
 JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_ARRAY_LENGTH);
 JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH + 1 == JSSLOT_ARRAY_COUNT);
 
 JSObject* JS_FASTCALL
 js_NewEmptyArray(JSContext* cx, JSObject* proto)
 {
     JS_ASSERT(OBJ_IS_ARRAY(cx, proto));
 
-    JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
+    JSObject* obj = js_NewGCObject(cx);
     if (!obj)
         return NULL;
 
     /* Initialize all fields of JSObject. */
     obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
     obj->classword = jsuword(&js_ArrayClass);
     obj->setProto(proto);
     obj->setParent(proto->getParent());
@@ -3458,17 +3458,17 @@ js_NewArrayObject(JSContext *cx, jsuint 
         return NULL;
 
     JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
     if (!InitArrayObject(cx, obj, length, vector, holey))
         obj = NULL;
     JS_POP_TEMP_ROOT(cx, &tvr);
 
     /* Set/clear newborn root, in case we lost it.  */
-    cx->weakRoots.newborn[GCX_OBJECT] = obj;
+    cx->weakRoots.newbornObject = obj;
     return obj;
 }
 
 JSObject *
 js_NewSlowArrayObject(JSContext *cx)
 {
     JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL);
     if (obj)
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -402,17 +402,17 @@ js_NewNullClosure(JSContext* cx, JSObjec
 {
     JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
     JS_ASSERT(HAS_FUNCTION_CLASS(proto));
     JS_ASSERT(JS_ON_TRACE(cx));
 
     JSFunction *fun = (JSFunction*) funobj;
     JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
 
-    JSObject* closure = js_NewGCObject(cx, GCX_OBJECT);
+    JSObject* closure = js_NewGCObject(cx);
     if (!closure)
         return NULL;
 
     JSScope *scope = OBJ_SCOPE(proto)->getEmptyScope(cx, &js_FunctionClass);
     if (!scope) {
         JS_ASSERT(!closure->map);
         return NULL;
     }
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -102,17 +102,17 @@ typedef union JSLocalNames {
                                        JSFunctionSpec::call points to a
                                        JSNativeTraceInfo. */
 #define JSFUN_INTERPRETED   0x4000  /* use u.i if kind >= this value else u.n */
 #define JSFUN_FLAT_CLOSURE  0x8000  /* flag (aka "display") closure */
 #define JSFUN_NULL_CLOSURE  0xc000  /* null closure entrains no scope chain */
 #define JSFUN_KINDMASK      0xc000  /* encode interp vs. native and closure
                                        optimization level -- see above */
 
-#define FUN_OBJECT(fun)      (&(fun)->object)
+#define FUN_OBJECT(fun)      (static_cast<JSObject *>(fun))
 #define FUN_KIND(fun)        ((fun)->flags & JSFUN_KINDMASK)
 #define FUN_SET_KIND(fun,k)  ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k))
 #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED)
 #define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE)
 #define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE)
 #define FUN_SLOW_NATIVE(fun) (!FUN_INTERPRETED(fun) && !((fun)->flags & JSFUN_FAST_NATIVE))
 #define FUN_SCRIPT(fun)      (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL)
 #define FUN_NATIVE(fun)      (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL)
@@ -123,18 +123,17 @@ typedef union JSLocalNames {
                               ? 0                                             \
                               : (fun)->nargs)
 #define FUN_CLASP(fun)       (JS_ASSERT(!FUN_INTERPRETED(fun)),               \
                               fun->u.n.clasp)
 #define FUN_TRCINFO(fun)     (JS_ASSERT(!FUN_INTERPRETED(fun)),               \
                               JS_ASSERT((fun)->flags & JSFUN_TRCINFO),        \
                               fun->u.n.trcinfo)
 
-struct JSFunction {
-    JSObject        object;       /* GC'ed object header */
+struct JSFunction : public JSObject {
     uint16          nargs;        /* maximum number of specified arguments,
                                      reflected as f.length/f.arity */
     uint16          flags;        /* flags, see JSFUN_* below and in jsapi.h */
     union {
         struct {
             uint16      extra;    /* number of arg slots for local GC roots */
             uint16      spare;    /* reserved for future use */
             JSNative    native;   /* native method pointer or null */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1760,18 +1760,19 @@ IsGCThresholdReached(JSRuntime *rt)
      * Since the initial value of the gcLastBytes parameter is not equal to
      * zero (see the js_InitGC function) the return value is false when
      * the gcBytes value is close to zero at the JS engine start.
      */
     return rt->gcMallocBytes >= rt->gcMaxMallocBytes ||
            rt->gcBytes >= rt->gcTriggerBytes;
 }
 
-template <class T> static JS_INLINE T*
-NewGCThing(JSContext *cx, uintN flags)
+template <typename T, typename NewbornType>
+static JS_INLINE T*
+NewGCThing(JSContext *cx, uintN flags, NewbornType** newbornRoot)
 {
     JSRuntime *rt;
     bool doGC;
     JSGCThing *thing;
     uint8 *flagp;
     JSGCArenaList *arenaList;
     JSGCArenaInfo *a;
     uintN thingsLimit;
@@ -1990,17 +1991,17 @@ testReservedObjects:
             *flagp = GCF_FINAL;
             goto fail;
         }
     } else {
         /*
          * No local root scope, so we're stuck with the old, fragile model of
          * depending on a pigeon-hole newborn per type per context.
          */
-        cx->weakRoots.newborn[flags & GCF_TYPEMASK] = thing;
+        *newbornRoot = (T *) thing;
     }
 
     /* We can't fail now, so update flags. */
     *flagp = (uint8)flags;
 
 #ifdef DEBUG_gchist
     gchist[gchpos].lastDitch = doGC;
     gchist[gchpos].freeList = rt->gcArenaList[flindex].freeList;
@@ -2022,36 +2023,50 @@ fail:
     if (gcLocked)
         JS_UNLOCK_GC(rt);
 #endif
     METER(astats->fail++);
     js_ReportOutOfMemory(cx);
     return NULL;
 }
 
-extern JSObject* js_NewGCObject(JSContext *cx, uintN flags)
+JSObject *
+js_NewGCObject(JSContext *cx)
 {
-    return NewGCThing<JSObject>(cx, flags);
+    return NewGCThing<JSObject>(cx, GCX_OBJECT, &cx->weakRoots.newbornObject);
 }
 
-extern JSString* js_NewGCString(JSContext *cx, uintN flags)
+JSString *
+js_NewGCString(JSContext *cx)
 {
-    return NewGCThing<JSString>(cx, flags);
+    return NewGCThing<JSString>(cx, GCX_STRING, &cx->weakRoots.newbornString);
 }
 
-extern JSFunction* js_NewGCFunction(JSContext *cx, uintN flags)
+JSString *
+js_NewGCExternalString(JSContext *cx, uintN type)
 {
-    return NewGCThing<JSFunction>(cx, flags);
+    JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT);
+    return NewGCThing<JSString>(cx, GCX_EXTERNAL_STRING + type,
+                                &cx->weakRoots.newbornExternalString[type]);
 }
 
-extern JSXML* js_NewGCXML(JSContext *cx, uintN flags)
+JSFunction *
+js_NewGCFunction(JSContext *cx)
 {
-    return NewGCThing<JSXML>(cx, flags);
+    return NewGCThing<JSFunction>(cx, GCX_OBJECT, &cx->weakRoots.newbornObject);
 }
 
+#if JS_HAS_XML_SUPPORT
+JSXML *
+js_NewGCXML(JSContext *cx)
+{
+    return NewGCThing<JSXML>(cx, GCX_XML, &cx->weakRoots.newbornXML);
+}
+#endif
+
 static JSGCDoubleCell *
 RefillDoubleFreeList(JSContext *cx)
 {
     JSRuntime *rt;
     jsbitmap *doubleFlags, usedBits;
     JSBool didGC = JS_FALSE;
     JSGCArenaInfo *a;
     uintN bit, index;
@@ -2219,33 +2234,33 @@ js_NewWeaklyRootedDouble(JSContext *cx, 
         return NULL;
 
     JS_ASSERT(JSVAL_IS_DOUBLE(v));
     dp = JSVAL_TO_DOUBLE(v);
     if (cx->localRootStack) {
         if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0)
             return NULL;
     } else {
-        cx->weakRoots.newborn[GCX_DOUBLE] = dp;
+        cx->weakRoots.newbornDouble = dp;
     }
     return dp;
 }
 
 #ifdef JS_TRACER
 JSBool
 js_ReserveObjects(JSContext *cx, size_t nobjects)
 {
     /*
      * Ensure at least nobjects objects are in the list. fslots[1] of each
      * object on the reservedObjects list is the length of the list from there.
      */
     JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;
     size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;
     while (i < nobjects) {
-        JSObject *obj = js_NewGCObject(cx, GCX_OBJECT);
+        JSObject *obj = js_NewGCObject(cx);
         if (!obj)
             return JS_FALSE;
         memset(obj, 0, sizeof(JSObject));
         /* The class must be set to something for finalization. */
         obj->classword = (jsuword) &js_ObjectClass;
         obj->fslots[0] = OBJECT_TO_JSVAL(head);
         i++;
         obj->fslots[1] = INT_TO_JSVAL(i);
@@ -2884,43 +2899,31 @@ js_TraceStackFrame(JSTracer *trc, JSStac
     JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
     if (fp->scopeChain)
         JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
 }
 
 static void
 TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr)
 {
-    uint32 i;
-    void *thing;
-
-#ifdef DEBUG
-    static const char *weakRootNames[JSTRACE_LIMIT] = {
-        "newborn object",
-        "newborn double",
-        "newborn string",
-        "newborn xml"
-    };
+    if (wr->newbornObject)
+        JS_CALL_OBJECT_TRACER(trc, wr->newbornObject, "newborn_object");
+    if (wr->newbornString)
+        JS_CALL_STRING_TRACER(trc, wr->newbornString, "newborn_string");
+    if (wr->newbornDouble)
+        JS_CALL_DOUBLE_TRACER(trc, wr->newbornDouble, "newborn_double");
+#if JS_HAS_XML_SUPPORT
+    if (wr->newbornXML)
+        JS_CALL_TRACER(trc, wr->newbornXML, JSTRACE_XML, "newborn_xml");
 #endif
-
-    for (i = 0; i != JSTRACE_LIMIT; i++) {
-        thing = wr->newborn[i];
-        if (thing)
-            JS_CALL_TRACER(trc, thing, i, weakRootNames[i]);
+    for (uint32 i = 0; i != JS_EXTERNAL_STRING_LIMIT; i++) {
+        JSString *str = wr->newbornExternalString[i];
+        if (str)
+            JS_CALL_STRING_TRACER(trc, str, "newborn_external_string");
     }
-    JS_ASSERT(i == GCX_EXTERNAL_STRING);
-    for (; i != GCX_NTYPES; ++i) {
-        thing = wr->newborn[i];
-        if (thing) {
-            JS_SET_TRACING_INDEX(trc, "newborn external string",
-                                 i - GCX_EXTERNAL_STRING);
-            JS_CallTracer(trc, thing, JSTRACE_STRING);
-        }
-    }
-
     JS_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom");
     JS_SET_TRACING_NAME(trc, "lastInternalResult");
     js_CallValueTracerIfGCThing(trc, wr->lastInternalResult);
 }
 
 JS_REQUIRES_STACK JS_FRIEND_API(void)
 js_TraceContext(JSTracer *trc, JSContext *acx)
 {
@@ -3208,30 +3211,29 @@ FinalizeObject(JSContext *cx, JSObject *
         jsdtrace_object_finalize(obj);
 #endif
 
     if (JS_LIKELY(OBJ_IS_NATIVE(obj)))
         OBJ_SCOPE(obj)->drop(cx, obj);
     js_FreeSlots(cx, obj);
 }
 
-static JSStringFinalizeOp str_finalizers[GCX_NTYPES - GCX_EXTERNAL_STRING] = {
+JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
+static JSStringFinalizeOp str_finalizers[JS_EXTERNAL_STRING_LIMIT] = {
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
 intN
 js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
                                  JSStringFinalizeOp newop)
 {
-    uintN i;
-
-    for (i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
+    for (uintN i = 0; i != JS_ARRAY_LENGTH(str_finalizers); i++) {
         if (str_finalizers[i] == oldop) {
             str_finalizers[i] = newop;
-            return (intN) i;
+            return intN(i);
         }
     }
     return -1;
 }
 
 /*
  * cx is NULL when we are called from js_FinishAtomState to force the
  * finalization of the permanently interned strings.
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -63,21 +63,23 @@ JS_BEGIN_EXTERN_C
  * strings.
  */
 #define GCX_OBJECT              JSTRACE_OBJECT      /* JSObject */
 #define GCX_DOUBLE              JSTRACE_DOUBLE      /* jsdouble */
 #define GCX_STRING              JSTRACE_STRING      /* JSString */
 #define GCX_XML                 JSTRACE_XML         /* JSXML */
 #define GCX_EXTERNAL_STRING     JSTRACE_LIMIT       /* JSString with external
                                                        chars */
+const uintN JS_EXTERNAL_STRING_LIMIT = 8;
+
 /*
  * The number of defined GC types and the maximum limit for the number of
  * possible GC types.
  */
-#define GCX_NTYPES              (GCX_EXTERNAL_STRING + 8)
+#define GCX_NTYPES              (GCX_EXTERNAL_STRING + JS_EXTERNAL_STRING_LIMIT)
 #define GCX_LIMIT_LOG2         4           /* type index bits */
 #define GCX_LIMIT              JS_BIT(GCX_LIMIT_LOG2)
 
 /* GC flag definitions, must fit in 8 bits (type index goes in the low bits). */
 #define GCF_TYPEMASK    JS_BITMASK(GCX_LIMIT_LOG2)
 #define GCF_MARK        JS_BIT(GCX_LIMIT_LOG2)
 #define GCF_FINAL       JS_BIT(GCX_LIMIT_LOG2 + 1)
 #define GCF_LOCKSHIFT   (GCX_LIMIT_LOG2 + 2)   /* lock bit shift */
@@ -164,26 +166,29 @@ struct JSGCThing {
 
 /*
  * Allocates a new GC thing of the given size. After a successful allocation
  * the caller must fully initialize the thing before calling any function that
  * can potentially trigger GC. This will ensure that GC tracing never sees junk
  * values stored in the partially initialized thing.
  */
 extern JSObject*
-js_NewGCObject(JSContext *cx, uintN flags);
+js_NewGCObject(JSContext *cx);
+
+extern JSString*
+js_NewGCString(JSContext *cx);
 
 extern JSString*
-js_NewGCString(JSContext *cx, uintN flags);
+js_NewGCExternalString(JSContext *cx, uintN type);
 
 extern JSFunction*
-js_NewGCFunction(JSContext *cx, uintN flags);
+js_NewGCFunction(JSContext *cx);
 
 extern JSXML*
-js_NewGCXML(JSContext *cx, uintN flags);
+js_NewGCXML(JSContext *cx);
 
 /*
  * Allocate a new double jsval and store the result in *vp. vp must be a root.
  * The function does not copy the result into any weak root.
  */
 extern JSBool
 js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp);
 
@@ -310,17 +315,23 @@ typedef struct JSGCDoubleArenaList {
                                            things */
 } JSGCDoubleArenaList;
 
 extern void
 js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data);
 
 struct JSWeakRoots {
     /* Most recently created things by type, members of the GC's root set. */
-    void            *newborn[GCX_NTYPES];
+    JSObject        *newbornObject;
+    jsdouble        *newbornDouble;
+    JSString        *newbornString;
+#if JS_HAS_XML_SUPPORT
+    JSXML           *newbornXML;
+#endif
+    JSString        *newbornExternalString[JS_EXTERNAL_STRING_LIMIT];
 
     /* Atom root for the last-looked-up atom on this context. */
     jsval           lastAtom;
 
     /* Root for the result of the most recent js_InternalInvoke call. */
     jsval           lastInternalResult;
 };
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2206,24 +2206,24 @@ js_NewObjectWithGivenProto(JSContext *cx
 
     /*
      * Allocate an object from the GC heap and initialize all its fields before
      * doing any operation that can potentially trigger GC. Functions have a
      * larger non-standard allocation size.
      */
     JSObject* obj;
     if (clasp == &js_FunctionClass && !objectSize) {
-        obj = (JSObject*) js_NewGCFunction(cx, GCX_OBJECT);
+        obj = (JSObject*) js_NewGCFunction(cx);
 #ifdef DEBUG
         memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
                sizeof(JSFunction) - sizeof(JSObject));
 #endif
     } else {
         JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
-        obj = js_NewGCObject(cx, GCX_OBJECT);
+        obj = 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.
      */
@@ -2238,29 +2238,29 @@ js_NewObjectWithGivenProto(JSContext *cx
             goto out;
         }
     } else {
         JS_ASSERT(ops->objectMap->ops == ops);
         obj->map = const_cast<JSObjectMap *>(ops->objectMap);
     }
 
     /* Check that the newborn root still holds the object. */
-    JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
+    JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newbornObject == obj);
 
     /*
      * Do not call debug hooks on trace, because we might be in a non-_FAIL
      * builtin. See bug 481444.
      */
     if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
         JSAutoTempValueRooter tvr(cx, obj);
         JS_KEEP_ATOMS(cx->runtime);
         cx->debugHooks->objectHook(cx, obj, JS_TRUE,
                                    cx->debugHooks->objectHookData);
         JS_UNKEEP_ATOMS(cx->runtime);
-        cx->weakRoots.newborn[GCX_OBJECT] = obj;
+        cx->weakRoots.newbornObject = obj;
     }
 
 out:
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
         jsdtrace_object_create(cx, clasp, obj);
     if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
         jsdtrace_object_create_done(cx->fp, clasp);
@@ -2315,17 +2315,17 @@ js_Object(JSContext *cx, JSObject *obj, 
 
 #ifdef JS_TRACER
 
 static inline JSObject*
 NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto,
                 JSObject *parent, jsval privateSlotValue)
 {
     JS_ASSERT(JS_ON_TRACE(cx));
-    JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
+    JSObject* obj = js_NewGCObject(cx);
     if (!obj)
         return NULL;
 
     obj->init(clasp, proto, parent, privateSlotValue);
     return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
 }
 
 JSObject* FASTCALL
@@ -2654,17 +2654,17 @@ js_NewBlockObject(JSContext *cx)
 }
 
 JSObject *
 js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
 {
     JS_ASSERT(!OBJ_IS_CLONED_BLOCK(proto));
     JS_ASSERT(STOBJ_GET_CLASS(proto) == &js_BlockClass);
 
-    JSObject *clone = js_NewGCObject(cx, GCX_OBJECT);
+    JSObject *clone = js_NewGCObject(cx);
     if (!clone)
         return NULL;
 
     JSScope *scope = OBJ_SCOPE(proto);
     scope->hold();
     JS_ASSERT(!scope->owned());
     clone->map = scope;
 
@@ -3254,17 +3254,17 @@ js_GetClassId(JSContext *cx, JSClass *cl
 JSObject*
 js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto,
                    jsval privateSlotValue)
 {
     JS_ASSERT(!clasp->getObjectOps);
     JS_ASSERT(proto->map->ops == &js_ObjectOps);
     JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
 
-    JSObject* obj = js_NewGCObject(cx, GCX_OBJECT);
+    JSObject* obj = js_NewGCObject(cx);
     if (!obj)
         return NULL;
 
     JSScope *scope = OBJ_SCOPE(proto)->getEmptyScope(cx, clasp);
     if (!scope) {
         JS_ASSERT(!obj->map);
         return NULL;
     }
@@ -5503,17 +5503,17 @@ js_GetClassPrototype(JSContext *cx, JSOb
              * Set the newborn root in case v is otherwise unreferenced.
              * It's ok to overwrite newborn roots here, since the getter
              * called just above could have.  Unlike the common GC rooting
              * model, our callers do not have to protect protop thanks to
              * this newborn root, since they all immediately create a new
              * instance that delegates to this object, or just query the
              * prototype for its class.
              */
-            cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(v);
+            cx->weakRoots.newbornObject = JSVAL_TO_OBJECT(v);
         }
     }
     *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL;
     return JS_TRUE;
 }
 
 /*
  * For shared precompilation of function objects, we support cloning on entry
--- a/js/src/jsops.cpp
+++ b/js/src/jsops.cpp
@@ -3478,17 +3478,17 @@
             CHECK_INTERRUPT_HANDLER();
           END_CASE(JSOP_NEWINIT)
 
           BEGIN_CASE(JSOP_ENDINIT)
             /* Re-set the newborn root to the top of this object tree. */
             JS_ASSERT(regs.sp - StackBase(fp) >= 1);
             lval = FETCH_OPND(-1);
             JS_ASSERT(JSVAL_IS_OBJECT(lval));
-            cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
+            cx->weakRoots.newbornObject = JSVAL_TO_OBJECT(lval);
           END_CASE(JSOP_ENDINIT)
 
           BEGIN_CASE(JSOP_INITPROP)
           BEGIN_CASE(JSOP_INITMETHOD)
             /* Load the property's initial value into rval. */
             JS_ASSERT(regs.sp - StackBase(fp) >= 2);
             rval = FETCH_OPND(-1);
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3020,17 +3020,17 @@ js_NewString(JSContext *cx, jschar *char
                 return NULL;
 
             js_LeaveTrace(cx);
         }
         js_ReportAllocationOverflow(cx);
         return NULL;
     }
 
-    str = js_NewGCString(cx, GCX_STRING);
+    str = js_NewGCString(cx);
     if (!str)
         return NULL;
     str->initFlat(chars, length);
 #ifdef DEBUG
   {
     JSRuntime *rt = cx->runtime;
     JS_RUNTIME_METER(rt, liveStrings);
     JS_RUNTIME_METER(rt, totalStrings);
@@ -3090,17 +3090,17 @@ js_NewDependentString(JSContext *cx, JSS
     if (start == 0 && length == base->length())
         return base;
 
     if (start > JSString::MAX_DEPENDENT_START ||
         (start != 0 && length > JSString::MAX_DEPENDENT_LENGTH)) {
         return js_NewStringCopyN(cx, base->chars() + start, length);
     }
 
-    ds = js_NewGCString(cx, GCX_STRING);
+    ds = js_NewGCString(cx);
     if (!ds)
         return NULL;
     if (start == 0)
         ds->initPrefix(base, length);
     else
         ds->initDependent(base, start, length);
 #ifdef DEBUG
   {
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -3380,19 +3380,19 @@ Descendants(JSContext *cx, JSXML *xml, j
     if (!listobj)
         return NULL;
     list = (JSXML *) listobj->getPrivate();
     if (funid)
         return list;
 
     /*
      * Protect nameqn's object and strings from GC by linking list to it
-     * temporarily.  The cx->newborn[GCX_OBJECT] GC root protects listobj,
-     * which protects list.  Any other object allocations occuring beneath
-     * DescendantsHelper use local roots.
+     * temporarily.  The newborn GC root for the last allocated object
+     * protects listobj, which protects list. Any other object allocations
+     * occurring beneath DescendantsHelper use local roots.
      */
     list->name = nameqn;
     if (!js_EnterLocalRootScope(cx))
         return NULL;
     if (xml->xml_class == JSXML_CLASS_LIST) {
         ok = JS_TRUE;
         for (i = 0, n = xml->xml_kids.length; i < n; i++) {
             kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
@@ -7177,19 +7177,17 @@ XMLList(JSContext *cx, JSObject *obj, ui
 #ifdef DEBUG_notme
 JSCList xml_leaks = JS_INIT_STATIC_CLIST(&xml_leaks);
 uint32  xml_serial;
 #endif
 
 JSXML *
 js_NewXML(JSContext *cx, JSXMLClass xml_class)
 {
-    JSXML *xml;
-
-    xml = (JSXML *) js_NewGCXML(cx, GCX_XML);
+    JSXML *xml = js_NewGCXML(cx);
     if (!xml)
         return NULL;
 
     xml->object = NULL;
     xml->domnode = NULL;
     xml->parent = NULL;
     xml->name = NULL;
     xml->xml_class = xml_class;