Bug 767141 - Add a Rooted<Type> and use it to root some scary type manipulation. r=bhackett
authorSteve Fink <sfink@mozilla.com>
Thu, 28 Jun 2012 17:35:56 -0700
changeset 98017 8f15e352d4b4fa0ec9315938623365abfd75ea3b
parent 98016 0dd9559f15ff98a990e79cb204f76a1c88a72d8a
child 98018 b97cdd8008a0fafa73df3b26799b27fa335e205d
push id11322
push usersfink@mozilla.com
push dateSat, 30 Jun 2012 04:47:50 +0000
treeherdermozilla-inbound@8f15e352d4b4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs767141
milestone16.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
Bug 767141 - Add a Rooted<Type> and use it to root some scary type manipulation. r=bhackett
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/gc/Root.h
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jspubtd.h
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -380,16 +380,32 @@ void
 MarkValueRoot(JSTracer *trc, Value *v, const char *name)
 {
     JS_ROOT_MARKING_ASSERT(trc);
     JS_SET_TRACING_NAME(trc, name);
     MarkValueInternal(trc, v);
 }
 
 void
+MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name)
+{
+    JS_ROOT_MARKING_ASSERT(trc);
+    JS_SET_TRACING_NAME(trc, name);
+    if (v->isSingleObject()) {
+        JSObject *obj = v->singleObject();
+        MarkInternal(trc, &obj);
+        *v = types::Type::ObjectType(obj);
+    } else if (v->isTypeObject()) {
+        types::TypeObject *typeObj = v->typeObject();
+        MarkInternal(trc, &typeObj);
+        *v = types::Type::ObjectType(typeObj);
+    }
+}
+
+void
 MarkValueRange(JSTracer *trc, size_t len, EncapsulatedValue *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
         JS_SET_TRACING_INDEX(trc, name, i);
         MarkValueInternal(trc, vec[i].unsafeGet());
     }
 }
 
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -143,16 +143,19 @@ void
 MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name);
 
 inline void
 MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name)
 {
     MarkValueRootRange(trc, end - begin, begin, name);
 }
 
+void
+MarkTypeRoot(JSTracer *trc, types::Type *v, const char *name);
+
 bool
 IsValueMarked(Value *v);
 
 /*** Slot Marking ***/
 
 void
 MarkSlot(JSTracer *trc, HeapSlot *s, const char *name);
 
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -135,35 +135,33 @@ struct RootMethods<T *>
 /*
  * Local variable of type T whose value is always rooted. This is typically
  * used for local variables, or for non-rooted values being passed to a
  * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
  */
 template <typename T>
 class Rooted
 {
-    void init(JSContext *cx_, T initial)
+    void init(JSContext *cx_)
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         ContextFriendFields *cx = ContextFriendFields::get(cx_);
 
         ThingRootKind kind = RootMethods<T>::kind();
         this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
         this->prev = *stack;
         *stack = this;
 
-        JS_ASSERT(!RootMethods<T>::poisoned(initial));
+        JS_ASSERT(!RootMethods<T>::poisoned(ptr));
 #endif
-
-        ptr = initial;
     }
 
   public:
-    Rooted(JSContext *cx) { init(cx, RootMethods<T>::initial()); }
-    Rooted(JSContext *cx, T initial) { init(cx, initial); }
+    Rooted(JSContext *cx) : ptr(RootMethods<T>::initial()) { init(cx); }
+    Rooted(JSContext *cx, T initial) : ptr(initial) { init(cx); }
 
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
 #endif
     }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -878,16 +878,18 @@ MarkExactStackRoots(JSTracer *trc)
                     } else if (i == THING_ROOT_STRING) {
                         MarkStringRoot(trc, (JSString **)addr, "exact stackroot string");
                     } else if (i == THING_ROOT_ID) {
                         MarkIdRoot(trc, (jsid *)addr, "exact stackroot id");
                     } else if (i == THING_ROOT_PROPERTY_ID) {
                         MarkIdRoot(trc, ((PropertyId *)addr)->asId(), "exact stackroot property id");
                     } else if (i == THING_ROOT_VALUE) {
                         MarkValueRoot(trc, (Value *)addr, "exact stackroot value");
+                    } else if (i == THING_ROOT_TYPE) {
+                        MarkTypeRoot(trc, (Type)addr, "exact stackroot type");
                     } else if (i == THING_ROOT_SHAPE) {
                         MarkShapeRoot(trc, (Shape **)addr, "exact stackroot shape");
                     } else if (i == THING_ROOT_BASE_SHAPE) {
                         MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact stackroot baseshape");
                     } else if (i == THING_ROOT_TYPE_OBJECT) {
                         MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact stackroot typeobject");
                     } else if (i == THING_ROOT_SCRIPT) {
                         MarkScriptRoot(trc, (JSScript **)addr, "exact stackroot script");
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2452,28 +2452,38 @@ TypeCompartment::fixArrayType(JSContext 
     ArrayTableKey key;
     key.type = type;
     key.proto = obj->getProto();
     ArrayTypeTable::AddPtr p = arrayTypeTable->lookupForAdd(key);
 
     if (p) {
         obj->setType(p->value);
     } else {
+        Rooted<Type> origType(cx, type);
         /* Make a new type to use for future arrays with the same elements. */
-        TypeObject *objType = newTypeObject(cx, NULL, JSProto_Array, obj->getProto());
-        AssertRootingUnnecessary safe(cx);
+        Rooted<TypeObject*> objType(cx, newTypeObject(cx, NULL, JSProto_Array, obj->getProto()));
         if (!objType) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
         obj->setType(objType);
 
         if (!objType->unknownProperties())
             objType->addPropertyType(cx, JSID_VOID, type);
 
+        // The key's fields may have been moved by moving GC and therefore the
+        // AddPtr is now invalid. ArrayTypeTable's equality and hashcodes
+        // operators use only the two fields (type and proto) directly, so we
+        // can just conditionally update them here.
+        if (type != origType || key.proto != obj->getProto()) {
+            key.type = origType;
+            key.proto = obj->getProto();
+            p = arrayTypeTable->lookupForAdd(key);
+        }
+
         if (!arrayTypeTable->relookupOrAdd(p, key, objType)) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
     }
 }
 
 /*
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1263,11 +1263,31 @@ inline const char * TypeObjectString(Typ
 /* Print a warning, dump state and abort the program. */
 MOZ_NORETURN void TypeFailure(JSContext *cx, const char *fmt, ...);
 
 } /* namespace types */
 } /* namespace js */
 
 namespace JS {
     template<> class AnchorPermitted<js::types::TypeObject *> { };
+
+template <> struct RootMethods<const js::types::Type>
+    {
+        static js::types::Type initial() { return js::types::Type::UnknownType(); }
+        static ThingRootKind kind() { return THING_ROOT_TYPE; }
+        static bool poisoned(const js::types::Type &v) {
+            return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
+                || (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
+        }
+    };
+
+    template <> struct RootMethods<js::types::Type>
+    {
+        static js::types::Type initial() { return js::types::Type::UnknownType(); }
+        static ThingRootKind kind() { return THING_ROOT_TYPE; }
+        static bool poisoned(const js::types::Type &v) {
+            return (v.isTypeObject() && IsPoisonedPtr(v.typeObject()))
+                || (v.isSingleObject() && IsPoisonedPtr(v.singleObject()));
+        }
+    };
 }
 
 #endif // jsinfer_h___
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -227,16 +227,17 @@ enum ThingRootKind
     THING_ROOT_BASE_SHAPE,
     THING_ROOT_TYPE_OBJECT,
     THING_ROOT_STRING,
     THING_ROOT_SCRIPT,
     THING_ROOT_XML,
     THING_ROOT_ID,
     THING_ROOT_PROPERTY_ID,
     THING_ROOT_VALUE,
+    THING_ROOT_TYPE,
     THING_ROOT_LIMIT
 };
 
 struct ContextFriendFields {
     JSRuntime *const    runtime;
 
     ContextFriendFields(JSRuntime *rt)
       : runtime(rt) { }