Bug 815999 - Mark gray globals black before returning them to the debugger (r=mccr8)
authorBill McCloskey <wmccloskey@mozilla.com>
Mon, 03 Dec 2012 17:59:46 -0800
changeset 123973 97bdf3a661775bd1ad5ccf1e9fc39eee495d519d
parent 123972 f2e450529466d11b6fc95387458c834fdf0531b9
child 123974 5dcf727f6fba99843eca0bf392222779ddee7da6
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs815999
milestone20.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 815999 - Mark gray globals black before returning them to the debugger (r=mccr8)
js/public/HeapAPI.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/vm/Debugger.cpp
js/xpconnect/src/xpcpublic.h
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -2,16 +2,18 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_heap_api_h___
 #define js_heap_api_h___
 
+#include "jsfriendapi.h"
+
 /* These values are private to the JS engine. */
 namespace js {
 namespace gc {
 
 /*
  * Page size must be static to support our arena pointer optimizations, so we
  * are forced to support each platform with non-4096 pages as a special case.
  * Note: The freelist supports a maximum arena shift of 15.
@@ -66,11 +68,28 @@ GetGCThingCompartment(void *thing)
 }
 
 static inline JSCompartment *
 GetObjectCompartment(JSObject *obj)
 {
     return GetGCThingCompartment(obj);
 }
 
+/*
+ * This should be called when an object that is marked gray is exposed to the JS
+ * engine (by handing it to running JS code or writing it into live JS
+ * data). During incremental GC, since the gray bits haven't been computed yet,
+ * we conservatively mark the object black.
+ */
+static JS_ALWAYS_INLINE void
+ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
+{
+    JS_ASSERT(kind != JSTRACE_SHAPE);
+
+    if (js::GCThingIsMarkedGray(thing))
+        js::UnmarkGrayGCThingRecursively(thing, kind);
+    else if (js::IsIncrementalBarrierNeededOnGCThing(thing, kind))
+        js::IncrementalReferenceBarrier(thing);
+}
+
 } /* namespace JS */
 
 #endif /* js_heap_api_h___ */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -889,25 +889,19 @@ js::IsIncrementalBarrierNeeded(JSRuntime
 
 JS_FRIEND_API(bool)
 js::IsIncrementalBarrierNeeded(JSContext *cx)
 {
     return IsIncrementalBarrierNeeded(cx->runtime);
 }
 
 JS_FRIEND_API(bool)
-js::IsIncrementalBarrierNeededOnObject(RawObject obj)
+js::IsIncrementalBarrierNeededOnGCThing(void *thing, JSGCTraceKind kind)
 {
-    return obj->compartment()->needsBarrier();
-}
-
-JS_FRIEND_API(bool)
-js::IsIncrementalBarrierNeededOnScript(JSScript *script)
-{
-    return script->compartment()->needsBarrier();
+    return static_cast<gc::Cell *>(thing)->compartment()->needsBarrier();
 }
 
 JS_FRIEND_API(void)
 js::IncrementalReferenceBarrier(void *ptr)
 {
     if (!ptr)
         return;
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -7,18 +7,16 @@
 #ifndef jsfriendapi_h___
 #define jsfriendapi_h___
 
 #include "jsclass.h"
 #include "jscpucfg.h"
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
-#include "js/HeapAPI.h"
-
 #include "mozilla/GuardObjects.h"
 
 /*
  * This macro checks if the stack pointer has exceeded a given limit. If
  * |tolerance| is non-zero, it returns true only if the stack pointer has
  * exceeded the limit by more than |tolerance| bytes.
  */
 #if JS_STACK_GROWTH_DIRECTION > 0
@@ -888,20 +886,17 @@ DisableIncrementalGC(JSRuntime *rt);
 
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSRuntime *rt);
 
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSContext *cx);
 
 extern JS_FRIEND_API(bool)
-IsIncrementalBarrierNeededOnObject(RawObject obj);
-
-extern JS_FRIEND_API(bool)
-IsIncrementalBarrierNeededOnScript(JSScript *obj);
+IsIncrementalBarrierNeededOnGCThing(void *thing, JSGCTraceKind kind);
 
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr);
 
 extern JS_FRIEND_API(void)
 IncrementalValueBarrier(const Value &v);
 
 extern JS_FRIEND_API(void)
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2494,16 +2494,23 @@ Debugger::findAllGlobals(JSContext *cx, 
     if (!result)
         return false;
 
     for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
         c->scheduledForDestruction = false;
 
         GlobalObject *global = c->maybeGlobal();
         if (global) {
+            /*
+             * We pulled |global| out of nowhere, so it's possible that it was
+             * marked gray by XPConnect. Since we're now exposing it to JS code,
+             * we need to mark it black.
+             */
+            ExposeGCThingToActiveJS(global, JSTRACE_OBJECT);
+
             Value globalValue(ObjectValue(*global));
             if (!dbg->wrapDebuggeeValue(cx, &globalValue))
                 return false;
             if (!js_NewbornArrayPush(cx, result, globalValue))
                 return false;
         }
     }
 
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -135,41 +135,35 @@ xpc_IsGrayGCThing(void *thing)
 // reachable from an XPConnect root. Implemented in nsXPConnect.cpp.
 extern JSBool
 xpc_GCThingIsGrayCCThing(void *thing);
 
 // Unmark gray for known-nonnull cases
 MOZ_ALWAYS_INLINE void
 xpc_UnmarkNonNullGrayObject(JSObject *obj)
 {
-    if (xpc_IsGrayGCThing(obj))
-        js::UnmarkGrayGCThingRecursively(obj, JSTRACE_OBJECT);
-    else if (js::IsIncrementalBarrierNeededOnObject(obj))
-        js::IncrementalReferenceBarrier(obj);
+    JS::ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
 }
 
 // Remove the gray color from the given JSObject and any other objects that can
 // be reached through it.
 MOZ_ALWAYS_INLINE JSObject *
 xpc_UnmarkGrayObject(JSObject *obj)
 {
     if (obj)
         xpc_UnmarkNonNullGrayObject(obj);
     return obj;
 }
 
 inline JSScript *
 xpc_UnmarkGrayScript(JSScript *script)
 {
-    if (script) {
-        if (xpc_IsGrayGCThing(script))
-            js::UnmarkGrayGCThingRecursively(script, JSTRACE_SCRIPT);
-        else if (js::IsIncrementalBarrierNeededOnScript(script))
-            js::IncrementalReferenceBarrier(script);
-    }
+    if (script)
+        JS::ExposeGCThingToActiveJS(script, JSTRACE_SCRIPT);
+
     return script;
 }
 
 inline JSContext *
 xpc_UnmarkGrayContext(JSContext *cx)
 {
     if (cx) {
         JSObject *global = JS_GetGlobalObject(cx);