[INFER] Use mark stack for type objects, bug 679887.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 26 Aug 2011 09:50:48 -0700
changeset 77462 407e7bdbedac52b4233aa0dea7262339531e9898
parent 77461 9a145389d5700137975faf65f2007e5f6c019121
child 77463 65562c596db33e91274748eb76e9686de63a29bc
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs679887
milestone9.0a1
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
[INFER] Use mark stack for type objects, bug 679887.
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcmark.cpp
js/src/jsgcmark.h
js/src/jsinfer.h
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -418,16 +418,17 @@ struct JSRuntime {
     int64               gcJitReleaseTime;
     JSGCMode            gcMode;
     volatile bool       gcIsNeeded;
     js::WeakMapBase     *gcWeakMapList;
 
     /* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
     void                *gcMarkStackObjs[js::OBJECT_MARK_STACK_SIZE / sizeof(void *)];
     void                *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)];
+    void                *gcMarkStackTypes[js::TYPE_MARK_STACK_SIZE / sizeof(void *)];
     void                *gcMarkStackXMLs[js::XML_MARK_STACK_SIZE / sizeof(void *)];
     void                *gcMarkStackLarges[js::LARGE_MARK_STACK_SIZE / sizeof(void *)];
 
     /*
      * Compartment that triggered GC. If more than one Compatment need GC,
      * gcTriggerCompartment is reset to NULL and a global GC is performed.
      */
     JSCompartment       *gcTriggerCompartment;
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -526,18 +526,17 @@ JSCompartment::markTypes(JSTracer *trc)
                     thing = span->last;
                     span = span->nextSpan();
                 } else if (isObjectKind) {
                     JSObject *object = reinterpret_cast<JSObject *>(thing);
                     if (object->lastProp && object->hasSingletonType())
                         MarkObject(trc, *object, "mark_types_singleton");
                 } else {
                     types::TypeObject *object = reinterpret_cast<types::TypeObject *>(thing);
-                    if (!object->isMarked())
-                        object->trace(trc);
+                    MarkTypeObject(trc, object, "object_root");
                 }
             }
         }
     }
 }
 
 void
 JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1532,16 +1532,17 @@ namespace js {
  * from the stack until it empties.
  */
 
 GCMarker::GCMarker(JSContext *cx)
   : color(0),
     unmarkedArenaStackTop(MarkingDelay::stackBottom()),
     objStack(cx->runtime->gcMarkStackObjs, sizeof(cx->runtime->gcMarkStackObjs)),
     ropeStack(cx->runtime->gcMarkStackRopes, sizeof(cx->runtime->gcMarkStackRopes)),
+    typeStack(cx->runtime->gcMarkStackTypes, sizeof(cx->runtime->gcMarkStackTypes)),
     xmlStack(cx->runtime->gcMarkStackXMLs, sizeof(cx->runtime->gcMarkStackXMLs)),
     largeStack(cx->runtime->gcMarkStackLarges, sizeof(cx->runtime->gcMarkStackLarges))
 {
     JS_TRACER_INIT(this, cx, NULL);
 #ifdef DEBUG
     markLaterArenas = 0;
 #endif
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
@@ -1793,18 +1794,17 @@ AutoGCRooter::trace(JSTracer *trc)
 
       case BINDINGS: {
         static_cast<js::AutoBindingsRooter *>(this)->bindings.trace(trc);
         return;
       }
 
       case TYPE: {
         types::TypeObject *type = static_cast<types::AutoTypeRooter *>(this)->type;
-        if (!type->isMarked())
-            type->trace(trc);
+        MarkTypeObject(trc, type, "js::AutoTypeRooter");
         return;
       }
 
       case VALARRAY: {
         AutoValueArray *array = static_cast<AutoValueArray *>(this);
         MarkValueRange(trc, array->length(), array->start(), "js::AutoValueArray");
         return;
       }
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1388,16 +1388,17 @@ struct LargeMarkItem
     uintN markpos;
 
     LargeMarkItem(JSObject *obj) : obj(obj), markpos(0) {}
 };
 
 static const size_t OBJECT_MARK_STACK_SIZE = 32768 * sizeof(JSObject *);
 static const size_t ROPES_MARK_STACK_SIZE = 1024 * sizeof(JSString *);
 static const size_t XML_MARK_STACK_SIZE = 1024 * sizeof(JSXML *);
+static const size_t TYPE_MARK_STACK_SIZE = 1024 * sizeof(types::TypeObject *);
 static const size_t LARGE_MARK_STACK_SIZE = 64 * sizeof(LargeMarkItem);
 
 struct GCMarker : public JSTracer {
   private:
     /* The color is only applied to objects, functions and xml. */
     uint32 color;
 
   public:
@@ -1411,16 +1412,17 @@ struct GCMarker : public JSTracer {
     js::gc::ConservativeGCStats conservativeStats;
     Vector<void *, 0, SystemAllocPolicy> conservativeRoots;
     const char *conservativeDumpFileName;
     void dumpConservativeRoots();
 #endif
 
     MarkStack<JSObject *> objStack;
     MarkStack<JSRope *> ropeStack;
+    MarkStack<types::TypeObject *> typeStack;
     MarkStack<JSXML *> xmlStack;
     MarkStack<LargeMarkItem> largeStack;
 
   public:
     explicit GCMarker(JSContext *cx);
     ~GCMarker();
 
     uint32 getMarkColor() const {
@@ -1435,32 +1437,38 @@ struct GCMarker : public JSTracer {
 
     void delayMarkingChildren(const void *thing);
 
     void markDelayedChildren();
 
     bool isMarkStackEmpty() {
         return objStack.isEmpty() &&
                ropeStack.isEmpty() &&
+               typeStack.isEmpty() &&
                xmlStack.isEmpty() &&
                largeStack.isEmpty();
     }
 
     JS_FRIEND_API(void) drainMarkStack();
 
     void pushObject(JSObject *obj) {
         if (!objStack.push(obj))
             delayMarkingChildren(obj);
     }
 
     void pushRope(JSRope *rope) {
         if (!ropeStack.push(rope))
             delayMarkingChildren(rope);
     }
 
+    void pushType(types::TypeObject *type) {
+        if (!typeStack.push(type))
+            delayMarkingChildren(type);
+    }
+
     void pushXML(JSXML *xml) {
         if (!xmlStack.push(xml))
             delayMarkingChildren(xml);
     }
 };
 
 void
 MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end);
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -95,16 +95,19 @@ static inline void
 PushMarkStack(GCMarker *gcmarker, const Shape *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSShortString *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSString *thing);
 
+static inline void
+PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing);
+
 template<typename T>
 static inline void
 CheckMarkedThing(JSTracer *trc, T *thing)
 {
     JS_ASSERT(thing);
     JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
     JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
@@ -140,51 +143,16 @@ Mark(JSTracer *trc, T *thing)
     }
 
 #ifdef DEBUG
     trc->debugPrinter = NULL;
     trc->debugPrintArg = NULL;
 #endif
 }
 
-/*
- * Alternative to Mark() which can be used when the thing is known to be in the
- * correct compartment (if we are in a per-compartment GC) and which is inline.
- */
-template<typename T>
-inline void
-InlineMark(JSTracer *trc, T *thing, const char *name)
-{
-    JS_SET_TRACING_NAME(trc, name);
-
-    CheckMarkedThing(trc, thing);
-
-    if (IS_GC_MARKING_TRACER(trc))
-        PushMarkStack(static_cast<GCMarker *>(trc), thing);
-    else
-        trc->callback(trc, (void *)thing, GetGCThingTraceKind(thing));
-
-#ifdef DEBUG
-    trc->debugPrinter = NULL;
-    trc->debugPrintArg = NULL;
-#endif
-}
-
-inline void
-InlineMarkId(JSTracer *trc, jsid id, const char *name)
-{
-    if (JSID_IS_STRING(id)) {
-        JSString *str = JSID_TO_STRING(id);
-        if (!str->isStaticAtom())
-            InlineMark(trc, str, name);
-    } else if (JS_UNLIKELY(JSID_IS_OBJECT(id))) {
-        InlineMark(trc, JSID_TO_OBJECT(id), name);
-    }
-}
-
 void
 MarkString(JSTracer *trc, JSString *str)
 {
     JS_ASSERT(str);
     if (str->isStaticAtom())
         return;
     Mark(trc, str);
 }
@@ -230,16 +198,35 @@ void
 MarkShape(JSTracer *trc, const Shape *shape, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(shape);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, shape);
 }
 
+void
+MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name)
+{
+    JS_ASSERT(trc);
+    JS_ASSERT(type);
+    JS_SET_TRACING_NAME(trc, name);
+    if (type == &types::emptyTypeObject)
+        return;
+    Mark(trc, type);
+
+    if (IS_GC_MARKING_TRACER(trc)) {
+        /* Mark parts of a type object skipped by ScanTypeObject. */
+        if (type->singleton)
+            MarkObject(trc, *type->singleton, "type_singleton");
+        if (type->functionScript)
+            js_TraceScript(trc, type->functionScript, NULL);
+    }
+}
+
 #if JS_HAS_XML_SUPPORT
 void
 MarkXML(JSTracer *trc, JSXML *xml, const char *name)
 {
     JS_ASSERT(trc);
     JS_ASSERT(xml);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, xml);
@@ -272,16 +259,26 @@ PushMarkStack(GCMarker *gcmarker, JSFunc
     JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
                  thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
 
     if (thing->markIfUnmarked(gcmarker->getMarkColor()))
         gcmarker->pushObject(thing);
 }
 
 void
+PushMarkStack(GCMarker *gcmarker, types::TypeObject *thing)
+{
+    JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
+                 thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
+
+    if (thing->markIfUnmarked(gcmarker->getMarkColor()))
+        gcmarker->pushType(thing);
+}
+
+void
 PushMarkStack(GCMarker *gcmarker, JSShortString *thing)
 {
     JS_ASSERT_IF(gcmarker->context->runtime->gcCurrentCompartment,
                  thing->compartment() == gcmarker->context->runtime->gcCurrentCompartment);
 
     (void) thing->markIfUnmarked(gcmarker->getMarkColor());
 }
 
@@ -377,16 +374,19 @@ MarkKind(JSTracer *trc, void *thing, uin
             Mark(trc, reinterpret_cast<JSObject *>(thing));
             break;
         case JSTRACE_STRING:
             MarkString(trc, reinterpret_cast<JSString *>(thing));
             break;
         case JSTRACE_SHAPE:
             Mark(trc, reinterpret_cast<Shape *>(thing));
             break;
+        case JSTRACE_TYPE_OBJECT:
+            Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
+            break;
 #if JS_HAS_XML_SUPPORT
         case JSTRACE_XML:
             Mark(trc, reinterpret_cast<JSXML *>(thing));
             break;
 #endif
         default:
             JS_ASSERT(false);
     }
@@ -511,22 +511,17 @@ void
 MarkRoot(JSTracer *trc, const Shape *thing, const char *name)
 {
     MarkShape(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, types::TypeObject *thing, const char *name)
 {
-    JS_ASSERT(trc);
-    JS_ASSERT(thing);
-    JS_SET_TRACING_NAME(trc, name);
-    JSRuntime *rt = trc->context->runtime;
-    if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment)
-        thing->trace(trc, false);
+    MarkTypeObject(trc, thing, name);
 }
 
 void
 MarkRoot(JSTracer *trc, JSXML *thing, const char *name)
 {
     MarkXML(trc, thing, name);
 }
 
@@ -662,33 +657,43 @@ static const uintN LARGE_OBJECT_CHUNK_SI
 
 static void
 ScanObject(GCMarker *gcmarker, JSObject *obj)
 {
     if (obj->isNewborn())
         return;
 
     types::TypeObject *type = obj->gctype();
-    if (type != &types::emptyTypeObject && !type->isMarked())
-        type->trace(gcmarker, /* weak = */ true);
+    if (type != &types::emptyTypeObject)
+        PushMarkStack(gcmarker, type);
 
     if (JSObject *parent = obj->getParent())
         PushMarkStack(gcmarker, parent);
-    if (!obj->isDenseArray() && obj->newType && !obj->newType->isMarked())
-        obj->newType->trace(gcmarker);
 
+    /*
+     * Call the trace hook if necessary, and check for a newType on objects
+     * which are not dense arrays (dense arrays have trace hooks).
+     */
     Class *clasp = obj->getClass();
     if (clasp->trace) {
-        if (obj->isDenseArray() && obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) {
-            if (!gcmarker->largeStack.push(LargeMarkItem(obj))) {
+        if (clasp == &js_ArrayClass) {
+            if (obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) {
+                if (!gcmarker->largeStack.push(LargeMarkItem(obj)))
+                    clasp->trace(gcmarker, obj);
+            } else {
                 clasp->trace(gcmarker, obj);
             }
         } else {
+            if (obj->newType)
+                PushMarkStack(gcmarker, obj->newType);
             clasp->trace(gcmarker, obj);
         }
+    } else {
+        if (obj->newType)
+            PushMarkStack(gcmarker, obj->newType);
     }
 
     if (obj->isNative()) {
         js::Shape *shape = obj->lastProp;
         PushMarkStack(gcmarker, shape);
 
         if (gcmarker->context->runtime->gcRegenShapes) {
             /* We need to regenerate our shape if hasOwnShape(). */
@@ -741,23 +746,21 @@ ScanLargeObject(GCMarker *gcmarker, Larg
 
 void
 MarkChildren(JSTracer *trc, JSObject *obj)
 {
     /* If obj has no map, it must be a newborn. */
     if (obj->isNewborn())
         return;
 
-    types::TypeObject *type = obj->gctype();
-    if (type != &types::emptyTypeObject)
-        type->trace(trc, /* weak = */ true);
+    MarkTypeObject(trc, obj->gctype(), "type");
 
     /* Trace universal (ops-independent) members. */
     if (!obj->isDenseArray() && obj->newType)
-        obj->newType->trace(trc);
+        MarkTypeObject(trc, obj->newType, "new_type");
     if (JSObject *parent = obj->getParent())
         MarkObject(trc, *parent, "parent");
 
     Class *clasp = obj->getClass();
     if (clasp->trace)
         clasp->trace(trc, obj);
 
     if (obj->isNative()) {
@@ -798,16 +801,91 @@ restart:
     if (shape->isMethod())
         MarkObjectWithPrinter(trc, shape->methodObject(), PrintPropertyMethod, shape, 0);
 
     shape = shape->previous();
     if (shape)
         goto restart;
 }
 
+static void
+ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
+{
+    if (!type->singleton) {
+        unsigned count = type->getPropertyCount();
+        for (unsigned i = 0; i < count; i++) {
+            types::Property *prop = type->getProperty(i);
+            if (prop && JSID_IS_STRING(prop->id)) {
+                JSString *str = JSID_TO_STRING(prop->id);
+                if (!str->isStaticAtom())
+                    PushMarkStack(gcmarker, str);
+            }
+        }
+    }
+
+    if (type->emptyShapes) {
+        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
+        for (int i = 0; i < count; i++) {
+            if (type->emptyShapes[i])
+                PushMarkStack(gcmarker, type->emptyShapes[i]);
+        }
+    }
+
+    if (type->proto)
+        PushMarkStack(gcmarker, type->proto);
+
+    if (type->newScript) {
+        js_TraceScript(gcmarker, type->newScript->script, NULL);
+        PushMarkStack(gcmarker, type->newScript->shape);
+    }
+
+    /*
+     * Don't need to trace singleton or functionScript, an object with this
+     * type must have already been traced and it will also hold a reference
+     * on the script (singleton and functionScript types cannot be the newType
+     * of another object). Attempts to mark type objects directly must use
+     * MarkTypeObject, which will itself mark these extra bits.
+     */
+}
+
+void
+MarkChildren(JSTracer *trc, types::TypeObject *type)
+{
+    if (!type->singleton) {
+        unsigned count = type->getPropertyCount();
+        for (unsigned i = 0; i < count; i++) {
+            types::Property *prop = type->getProperty(i);
+            if (prop)
+                MarkId(trc, prop->id, "type_prop");
+        }
+    }
+
+    if (type->emptyShapes) {
+        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
+        for (int i = 0; i < count; i++) {
+            if (type->emptyShapes[i])
+                MarkShape(trc, type->emptyShapes[i], "empty_shape");
+        }
+    }
+
+    if (type->proto)
+        MarkObject(trc, *type->proto, "type_proto");
+
+    if (type->singleton)
+        MarkObject(trc, *type->singleton, "type_singleton");
+
+    if (type->newScript) {
+        js_TraceScript(trc, type->newScript->script, NULL);
+        MarkShape(trc, type->newScript->shape, "type_new_shape");
+    }
+
+    if (type->functionScript)
+        js_TraceScript(trc, type->functionScript, NULL);
+}
+
 #ifdef JS_HAS_XML_SUPPORT
 void
 MarkChildren(JSTracer *trc, JSXML *xml)
 {
     js_TraceXML(trc, xml);
 }
 #endif
 
@@ -821,16 +899,19 @@ GCMarker::drainMarkStack()
 
     while (!isMarkStackEmpty()) {
         while (!ropeStack.isEmpty())
             ScanRope(this, ropeStack.pop());
 
         while (!objStack.isEmpty())
             ScanObject(this, objStack.pop());
 
+        while (!typeStack.isEmpty())
+            ScanTypeObject(this, typeStack.pop());
+
         while (!xmlStack.isEmpty())
             MarkChildren(this, xmlStack.pop());
 
         if (!largeStack.isEmpty()) {
             LargeMarkItem &item = largeStack.peek();
             if (ScanLargeObject(this, item))
                 largeStack.pop();
         }
@@ -860,77 +941,46 @@ JS_TraceChildren(JSTracer *trc, void *th
       case JSTRACE_STRING:
 	MarkChildren(trc, (JSString *)thing);
         break;
 
       case JSTRACE_SHAPE:
 	MarkChildren(trc, (js::Shape *)thing);
         break;
 
+      case JSTRACE_TYPE_OBJECT:
+        MarkChildren(trc, (types::TypeObject *)thing);
+        break;
+
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         MarkChildren(trc, (JSXML *)thing);
         break;
 #endif
     }
 }
 
 inline void
 JSObject::scanSlots(GCMarker *gcmarker)
 {
     /*
      * Scan the fixed slots and the dynamic slots separately, to avoid
      * branching inside nativeGetSlot().
      */
     JS_ASSERT(slotSpan() <= numSlots());
-    uint32 nslots = slotSpan();
-    uint32 nfixed = numFixedSlots();
-    uint32 i;
-    for (i = 0; i < nslots && i < nfixed; i++)
-        ScanValue(gcmarker, fixedSlots()[i]);
-    for (; i < nslots; i++)
-        ScanValue(gcmarker, slots[i - nfixed]);
-}
-
-void
-js::types::TypeObject::trace(JSTracer *trc, bool weak)
-{
-    /*
-     * Only mark types if the Mark/Sweep GC is running; the bit won't be
-     * cleared by the cycle collector. Also, don't mark for weak references
-     * from singleton JS objects, as if there are no outstanding refs we will
-     * destroy the type object and revert the JS object to a lazy type.
-     */
-    if (IS_GC_MARKING_TRACER(trc) && (!weak || !singleton)) {
-        JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment,
-                     compartment() == trc->context->runtime->gcCurrentCompartment);
-        markIfUnmarked(static_cast<GCMarker *>(trc)->getMarkColor());
-    }
-
-    unsigned count = getPropertyCount();
-    for (unsigned i = 0; i < count; i++) {
-        Property *prop = getProperty(i);
-        if (prop)
-            InlineMarkId(trc, prop->id, "type_prop");
-    }
-
-    if (emptyShapes) {
-        int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
-        for (int i = 0; i < count; i++) {
-            if (emptyShapes[i])
-                InlineMark(trc, emptyShapes[i], "empty_shape");
+    unsigned i, nslots = slotSpan();
+    if (slots) {
+        unsigned nfixed = numFixedSlots();
+        if (nslots > nfixed) {
+            Value *vp = fixedSlots();
+            for (i = 0; i < nfixed; i++, vp++)
+                ScanValue(gcmarker, *vp);
+            vp = slots;
+            for (; i < nslots; i++, vp++)
+                ScanValue(gcmarker, *vp);
+            return;
         }
     }
-
-    if (proto)
-        InlineMark(trc, proto, "type_proto");
-
-    if (singleton)
-        InlineMark(trc, singleton, "type_singleton");
-
-    if (newScript) {
-        js_TraceScript(trc, newScript->script, NULL);
-        InlineMark(trc, newScript->shape, "new_shape");
-    }
-
-    if (functionScript)
-        js_TraceScript(trc, functionScript, NULL);
+    JS_ASSERT(nslots <= numFixedSlots());
+    Value *vp = fixedSlots();
+    for (i = 0; i < nslots; i++, vp++)
+        ScanValue(gcmarker, *vp);
 }
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -72,16 +72,19 @@ MarkCrossCompartmentObject(JSTracer *trc
 void
 MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
 		      const void *arg, size_t index);
 
 void
 MarkShape(JSTracer *trc, const Shape *shape, const char *name);
 
 void
+MarkTypeObject(JSTracer *trc, types::TypeObject *type, const char *name);
+
+void
 MarkXML(JSTracer *trc, JSXML *xml, const char *name);
 
 void
 MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name);
 
 void
 MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name);
 
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -839,17 +839,16 @@ struct TypeObject : gc::Cell
     void markPropertyConfigured(JSContext *cx, jsid id);
     void markStateChange(JSContext *cx);
     void setFlags(JSContext *cx, TypeObjectFlags flags);
     void markUnknown(JSContext *cx);
     void clearNewScript(JSContext *cx);
     void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
 
     void print(JSContext *cx);
-    void trace(JSTracer *trc, bool weak = false);
 
     inline void clearProperties();
     inline void sweep(JSContext *cx);
 
     inline size_t dynamicSize();
 
     /*
      * Type objects don't have explicit finalizers. Memory owned by a type