Bug 1159465 - Automatically check for cross-compartment edges between objects when marking; r=jonco
authorTerrence Cole <terrence@mozilla.com>
Fri, 24 Apr 2015 16:15:30 -0700
changeset 273094 bcbd4118f34156bad7bff5779f8da8610029b6ef
parent 273093 250eb7785cf7d18037db0d1c21edc419d5bc8858
child 273095 15c5ec8215f76e0ab1601b651e89d100021ed8dc
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1159465
milestone40.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 1159465 - Automatically check for cross-compartment edges between objects when marking; r=jonco
js/src/gc/Marking.cpp
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -661,16 +661,27 @@ template <typename S, typename T>
 void
 js::GCMarker::traverse(S source, T target)
 {
     MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(target),
                   runtime()->isAtomsZone(target->zone()) || target->zone() == source->zone());
     traverse(target);
 }
 
+namespace js {
+// Special-case JSObject->JSObject edges to check the compartment too.
+template <>
+void
+GCMarker::traverse(JSObject* source, JSObject* target)
+{
+    MOZ_ASSERT(target->compartment() == source->compartment());
+    traverse(target);
+}
+} // namespace js
+
 template <typename V, typename S> struct TraverseFunctor : public VoidDefaultAdaptor<V> {
     template <typename T> void operator()(T t, GCMarker* gcmarker, S s) {
         return gcmarker->traverse(s, t);
     }
 };
 
 template <typename S>
 void
@@ -1626,30 +1637,27 @@ GCMarker::processMarkStackTop(SliceBudge
             JSString* str = *reinterpret_cast<JSString**>(unboxedMemory + *unboxedTraceList);
             traverse(obj, str);
             unboxedTraceList++;
         }
         unboxedTraceList++;
         while (*unboxedTraceList != -1) {
             JSObject* obj2 = *reinterpret_cast<JSObject**>(unboxedMemory + *unboxedTraceList);
             MOZ_ASSERT_IF(obj2, obj->compartment() == obj2->compartment());
-            if (obj2 && mark(obj2))
-                repush(obj2);
+            if (obj2)
+                traverse(obj, obj2);
             unboxedTraceList++;
         }
         unboxedTraceList++;
         while (*unboxedTraceList != -1) {
             const Value& v = *reinterpret_cast<Value*>(unboxedMemory + *unboxedTraceList);
             if (v.isString()) {
                 traverse(obj, v.toString());
             } else if (v.isObject()) {
-                JSObject* obj2 = &v.toObject();
-                MOZ_ASSERT(obj->compartment() == obj2->compartment());
-                if (mark(obj2))
-                    repush(obj2);
+                traverse(obj, &v.toObject());
             } else if (v.isSymbol()) {
                 traverse(obj, v.toSymbol());
             }
             unboxedTraceList++;
         }
         return;
     }
 
@@ -1659,69 +1667,69 @@ GCMarker::processMarkStackTop(SliceBudge
 
         budget.step();
         if (budget.isOverBudget()) {
             repush(obj);
             return;
         }
 
         ObjectGroup* group = obj->groupFromGC();
-        traverse(group);
+        traverse(obj, group);
 
         /* Call the trace hook if necessary. */
         const Class* clasp = group->clasp();
         if (clasp->trace) {
             // Global objects all have the same trace hook. That hook is safe without barriers
             // if the global has no custom trace hook of its own, or has been moved to a different
             // compartment, and so can't have one.
             MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
                             (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
                           clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             if (clasp->trace == InlineTypedObject::obj_trace) {
                 Shape* shape = obj->as<InlineTypedObject>().shapeFromGC();
-                traverse(shape);
+                traverse(obj, shape);
                 TypeDescr* descr = &obj->as<InlineTypedObject>().typeDescr();
                 if (!descr->hasTraceList())
                     return;
                 unboxedTraceList = descr->traceList();
                 unboxedMemory = obj->as<InlineTypedObject>().inlineTypedMem();
                 goto scan_unboxed;
             }
             if (clasp == &UnboxedPlainObject::class_) {
                 JSObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
-                if (expando && mark(expando))
-                    repush(expando);
+                if (expando)
+                    traverse(obj, expando);
                 const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
                 unboxedTraceList = layout.traceList();
                 if (!unboxedTraceList)
                     return;
                 unboxedMemory = obj->as<UnboxedPlainObject>().data();
                 goto scan_unboxed;
             }
             clasp->trace(this, obj);
         }
 
         if (!clasp->isNative())
             return;
 
         NativeObject* nobj = &obj->as<NativeObject>();
 
         Shape* shape = nobj->lastProperty();
-        traverse(shape);
+        traverse(obj, shape);
 
         unsigned nslots = nobj->slotSpan();
 
         do {
             if (nobj->hasEmptyElements())
                 break;
 
             if (nobj->denseElementsAreCopyOnWrite()) {
                 JSObject* owner = nobj->getElementsHeader()->ownerObject();
                 if (owner != nobj) {
-                    traverse(owner);
+                    traverse(obj, owner);
                     break;
                 }
             }
 
             vp = nobj->getDenseElementsAllowCopyOnWrite();
             end = vp + nobj->getDenseInitializedLength();
             if (!nslots)
                 goto scan_value_array;