Bug 1147533 - Add cross-compartment tracing methods via the new tracing paths; r=jonco
☠☠ backed out by 99415fbccf83 ☠ ☠
authorTerrence Cole <terrence@mozilla.com>
Thu, 26 Mar 2015 10:17:51 -0700
changeset 266633 be4138f208bad246fac8a198a56c2aec1e27dacc
parent 266632 6bbd529bd995bc89ac9b064bf33b81d3ce6cd342
child 266634 37c42cff2c013c8451224b8ea9d6bd8d958d4fc8
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1147533
milestone39.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 1147533 - Add cross-compartment tracing methods via the new tracing paths; r=jonco
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/proxy/Proxy.cpp
js/src/vm/Debugger.cpp
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -391,16 +391,18 @@ FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE);
 template <typename T> struct PtrBaseGCType {};
 template <> struct PtrBaseGCType<Value> { typedef Value type; };
 template <> struct PtrBaseGCType<jsid> { typedef jsid type; };
 template <typename T> struct PtrBaseGCType<T *> { typedef typename BaseGCType<T>::type *type; };
 
 template <typename T> void DispatchToTracer(JSTracer *trc, T *thingp, const char *name, size_t i);
 template <typename T> void DoTracing(JS::CallbackTracer *trc, T *thingp, const char *name, size_t i);
 template <typename T> void DoMarking(GCMarker *gcmarker, T thing);
+static bool ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell);
+static bool ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Value val);
 
 template <typename T>
 void
 js::TraceEdge(JSTracer *trc, BarrieredBase<T> *thingp, const char *name)
 {
     auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type *>(thingp->unsafeGet());
     DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
 }
@@ -448,16 +450,39 @@ js::TraceRootRange(JSTracer *trc, size_t
     template void js::TraceEdge<type>(JSTracer *, BarrieredBase<type> *, const char *); \
     template void js::TraceManuallyBarrieredEdge<type>(JSTracer *, type *, const char *); \
     template void js::TraceRoot<type>(JSTracer *, type *, const char *); \
     template void js::TraceRange<type>(JSTracer *, size_t, BarrieredBase<type> *, const char *); \
     template void js::TraceRootRange<type>(JSTracer *, size_t, type *, const char *);
 FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
 #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
 
+template <typename T>
+void
+js::TraceManuallyBarrieredCrossCompartmentEdge(JSTracer *trc, JSObject *src, T *dst,
+                                               const char *name)
+{
+    if (ShouldMarkCrossCompartment(trc, src, *dst))
+        DispatchToTracer(trc, dst, name, -1);
+}
+template void js::TraceManuallyBarrieredCrossCompartmentEdge<JSObject*>(JSTracer *, JSObject *,
+                                                                        JSObject **, const char *);
+template void js::TraceManuallyBarrieredCrossCompartmentEdge<JSScript*>(JSTracer *, JSObject *,
+                                                                        JSScript **, const char *);
+
+template <typename T>
+void
+js::TraceCrossCompartmentEdge(JSTracer *trc, JSObject *src, BarrieredBase<T> *dst, const char *name)
+{
+    if (ShouldMarkCrossCompartment(trc, src, dst->get()))
+        DispatchToTracer(trc, dst->unsafeGet(), name, -1);
+}
+template void js::TraceCrossCompartmentEdge<Value>(JSTracer *, JSObject *, BarrieredBase<Value> *,
+                                                   const char *);
+
 // This method is responsible for dynamic dispatch to the real tracer
 // implementation. Consider replacing this choke point with virtual dispatch:
 // a sufficiently smart C++ compiler may be able to devirtualize some paths.
 template <typename T>
 void
 DispatchToTracer(JSTracer *trc, T *thingp, const char *name, size_t i)
 {
 #define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type *, T>::value ||
@@ -1349,36 +1374,20 @@ ShouldMarkCrossCompartment(JSTracer *trc
             if (!tenured.isMarked())
                 DelayCrossCompartmentGrayMarking(src);
             return false;
         }
         return zone->isGCMarkingGray();
     }
 }
 
-void
-gc::MarkCrossCompartmentObjectUnbarriered(JSTracer *trc, JSObject *src, JSObject **dst, const char *name)
+static bool
+ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Value val)
 {
-    if (ShouldMarkCrossCompartment(trc, src, *dst))
-        MarkObjectUnbarriered(trc, dst, name);
-}
-
-void
-gc::MarkCrossCompartmentScriptUnbarriered(JSTracer *trc, JSObject *src, JSScript **dst,
-                                          const char *name)
-{
-    if (ShouldMarkCrossCompartment(trc, src, *dst))
-        MarkScriptUnbarriered(trc, dst, name);
-}
-
-void
-gc::MarkCrossCompartmentSlot(JSTracer *trc, JSObject *src, HeapValue *dst, const char *name)
-{
-    if (dst->isMarkable() && ShouldMarkCrossCompartment(trc, src, (Cell *)dst->toGCThing()))
-        MarkValue(trc, dst, name);
+    return val.isMarkable() && ShouldMarkCrossCompartment(trc, src, (Cell *)val.toGCThing());
 }
 
 /*** Special Marking ***/
 
 void
 gc::MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
 {
     trc->setTracingName(name);
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -34,36 +34,59 @@ template<class> class HeapPtr;
 namespace jit {
 class JitCode;
 struct IonScript;
 struct VMFunction;
 }
 
 /*** Tracing ***/
 
+// Trace through an edge in the live object graph on behalf of tracing. The
+// effect of tracing the edge depends on the JSTracer being used.
 template <typename T>
 void
 TraceEdge(JSTracer *trc, BarrieredBase<T> *thingp, const char *name);
 
+// Trace through a "root" edge. These edges are the initial edges in the object
+// graph traversal. Root edges are asserted to only be traversed in the initial
+// phase of a GC.
 template <typename T>
 void
 TraceRoot(JSTracer *trc, T *thingp, const char *name);
 
+// Like TraceEdge, but for edges that do not use one of the automatic barrier
+// classes and, thus, must be treated specially for moving GC. This method is
+// separate from TraceEdge to make accidental use of such edges more obvious.
 template <typename T>
 void
 TraceManuallyBarrieredEdge(JSTracer *trc, T *thingp, const char *name);
 
+// Trace all edges contained in the given array.
 template <typename T>
 void
 TraceRange(JSTracer *trc, size_t len, BarrieredBase<T> *thingp, const char *name);
 
+// Trace all root edges in the given array.
 template <typename T>
 void
 TraceRootRange(JSTracer *trc, size_t len, T *thingp, const char *name);
 
+// Trace an edge that crosses compartment boundaries. If the compartment of the
+// destination thing is not being GC'd, then the edge will not be traced.
+template <typename T>
+void
+TraceCrossCompartmentEdge(JSTracer *trc, JSObject *src, BarrieredBase<T> *dst,
+                          const char *name);
+
+// As above but with manual barriers.
+template <typename T>
+void
+TraceManuallyBarrieredCrossCompartmentEdge(JSTracer *trc, JSObject *src, T *dst,
+                                           const char *name);
+
 namespace gc {
 
 /*** Object Marking ***/
 
 /*
  * These functions expose marking functionality for all of the different GC
  * thing kinds. For each GC thing, there are several variants. As an example,
  * these are the variants generated for JSObject. They are listed from most to
@@ -250,32 +273,16 @@ void
 MarkSlot(JSTracer *trc, HeapSlot *s, const char *name);
 
 void
 MarkArraySlots(JSTracer *trc, size_t len, HeapSlot *vec, const char *name);
 
 void
 MarkObjectSlots(JSTracer *trc, NativeObject *obj, uint32_t start, uint32_t nslots);
 
-void
-MarkCrossCompartmentObjectUnbarriered(JSTracer *trc, JSObject *src, JSObject **dst_obj,
-                                      const char *name);
-
-void
-MarkCrossCompartmentScriptUnbarriered(JSTracer *trc, JSObject *src, JSScript **dst_script,
-                                      const char *name);
-
-/*
- * Mark a value that may be in a different compartment from the compartment
- * being GC'd. (Although it won't be marked if it's in the wrong compartment.)
- */
-void
-MarkCrossCompartmentSlot(JSTracer *trc, JSObject *src, HeapValue *dst_slot, const char *name);
-
-
 /*** Special Cases ***/
 
 /*
  * Trace through the shape and any shapes it contains to mark
  * non-shape children. This is exposed to the JS API as
  * JS_TraceShapeCycleCollectorChildren.
  */
 void
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -628,17 +628,17 @@ ProxyObject::trace(JSTracer *trc, JSObje
             MOZ_ASSERT(p);
             MOZ_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
         }
     }
 #endif
 
     // Note: If you add new slots here, make sure to change
     // nuke() to cope.
-    MarkCrossCompartmentSlot(trc, obj, proxy->slotOfPrivate(), "private");
+    TraceCrossCompartmentEdge(trc, obj, proxy->slotOfPrivate(), "private");
     MarkValue(trc, proxy->slotOfExtra(0), "extra0");
 
     /*
      * The GC can use the second reserved slot to link the cross compartment
      * wrappers into a linked list, in which case we don't want to trace it.
      */
     if (!proxy->is<CrossCompartmentWrapperObject>())
         MarkValue(trc, proxy->slotOfExtra(1), "extra1");
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4245,17 +4245,17 @@ GetScriptReferent(JSObject *obj)
     return static_cast<JSScript *>(obj->as<NativeObject>().getPrivate());
 }
 
 void
 DebuggerScript_trace(JSTracer *trc, JSObject *obj)
 {
     /* This comes from a private pointer, so no barrier needed. */
     if (JSScript *script = GetScriptReferent(obj)) {
-        MarkCrossCompartmentScriptUnbarriered(trc, obj, &script, "Debugger.Script referent");
+        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &script, "Debugger.Script referent");
         obj->as<NativeObject>().setPrivateUnbarriered(script);
     }
 }
 
 const Class DebuggerScript_class = {
     "Script",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT),
@@ -5267,17 +5267,18 @@ GetSourceReferent(JSObject *obj)
 void
 DebuggerSource_trace(JSTracer *trc, JSObject *obj)
 {
     /*
      * There is a barrier on private pointers, so the Unbarriered marking
      * is okay.
      */
     if (JSObject *referent = GetSourceReferent(obj)) {
-        MarkCrossCompartmentObjectUnbarriered(trc, obj, &referent, "Debugger.Source referent");
+        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+                                                   "Debugger.Source referent");
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerSource_class = {
     "Source",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT),
@@ -6383,17 +6384,18 @@ static const JSFunctionSpec DebuggerFram
 void
 DebuggerObject_trace(JSTracer *trc, JSObject *obj)
 {
     /*
      * There is a barrier on private pointers, so the Unbarriered marking
      * is okay.
      */
     if (JSObject *referent = (JSObject *) obj->as<NativeObject>().getPrivate()) {
-        MarkCrossCompartmentObjectUnbarriered(trc, obj, &referent, "Debugger.Object referent");
+        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+                                                   "Debugger.Object referent");
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerObject_class = {
     "Object",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT),
@@ -7292,17 +7294,18 @@ static const JSFunctionSpec DebuggerObje
 void
 DebuggerEnv_trace(JSTracer *trc, JSObject *obj)
 {
     /*
      * There is a barrier on private pointers, so the Unbarriered marking
      * is okay.
      */
     if (Env *referent = (JSObject *) obj->as<NativeObject>().getPrivate()) {
-        MarkCrossCompartmentObjectUnbarriered(trc, obj, &referent, "Debugger.Environment referent");
+        TraceManuallyBarrieredCrossCompartmentEdge(trc, obj, &referent,
+                                                   "Debugger.Environment referent");
         obj->as<NativeObject>().setPrivateUnbarriered(referent);
     }
 }
 
 const Class DebuggerEnv_class = {
     "Environment",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT),