Bug 913224 - Fix js::DumpHeapComplete() to work with GGC r=billm r=mccr8
☠☠ backed out by 90585002d95a ☠ ☠
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 30 Sep 2013 11:20:08 +0100
changeset 149252 3e20fa22242461722dc538a96de381282afdab04
parent 149251 4ebf2657b29509df0006b479c9c48beb87604ffb
child 149253 e9c35a179f6508c9d5dd63d950380c6bedd0d601
push id25380
push userryanvm@gmail.com
push dateMon, 30 Sep 2013 20:16:36 +0000
treeherdermozilla-central@1332fc1c15e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm, mccr8
bugs913224
milestone27.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 913224 - Fix js::DumpHeapComplete() to work with GGC r=billm r=mccr8
js/src/builtin/TestingFunctions.cpp
js/src/jit-test/tests/gc/bug-913224.js
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -822,42 +822,62 @@ FinalizeCount(JSContext *cx, unsigned ar
 {
     *vp = INT_TO_JSVAL(finalizeCount);
     return true;
 }
 
 static bool
 DumpHeapComplete(JSContext *cx, unsigned argc, jsval *vp)
 {
-    const char *fileName = nullptr;
-    JSAutoByteString fileNameBytes;
-    if (argc > 0) {
-        Value v = JS_ARGV(cx, vp)[0];
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    DumpHeapNurseryBehaviour nurseryBehaviour = js::IgnoreNurseryObjects;
+    FILE *dumpFile = NULL;
+
+    unsigned i = 0;
+    if (argc > i) {
+        Value v = args[i];
         if (v.isString()) {
             JSString *str = v.toString();
-            if (!fileNameBytes.encodeLatin1(cx, str))
+            bool same = false;
+            if (!JS_StringEqualsAscii(cx, str, "collectNurseryBeforeDump", &same))
                 return false;
-            fileName = fileNameBytes.ptr();
+            if (same) {
+                nurseryBehaviour = js::CollectNurseryBeforeDump;
+                ++i;
+            }
         }
     }
 
-    FILE *dumpFile;
-    if (!fileName) {
-        dumpFile = stdout;
-    } else {
-        dumpFile = fopen(fileName, "w");
-        if (!dumpFile) {
-            JS_ReportError(cx, "can't open %s", fileName);
-            return false;
+    if (argc > i) {
+        Value v = args[i];
+        if (v.isString()) {
+            JSString *str = v.toString();
+            JSAutoByteString fileNameBytes;
+            if (!fileNameBytes.encodeLatin1(cx, str))
+                return false;
+            const char *fileName = fileNameBytes.ptr();
+            dumpFile = fopen(fileName, "w");
+            if (!dumpFile) {
+                JS_ReportError(cx, "can't open %s", fileName);
+                return false;
+            }
+            ++i;
         }
     }
 
-    js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile);
+    if (i != argc) {
+        JS_ReportError(cx, "bad arguments passed to dumpHeapComplete");
+        return false;
+    }
 
-    fclose(dumpFile);
+    js::DumpHeapComplete(JS_GetRuntime(cx), dumpFile ? dumpFile : stdout, nurseryBehaviour);
+
+    if (dumpFile)
+        fclose(dumpFile);
 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 static bool
 Terminate(JSContext *cx, unsigned arg, jsval *vp)
 {
@@ -1179,18 +1199,20 @@ static const JSFunctionSpecWithHelp Test
 "  Query an internal constant for the engine. See InternalConst source for\n"
 "  the list of constant names."),
 
     JS_FN_HELP("isProxy", IsProxy, 1, 0,
 "isProxy(obj)",
 "  If true, obj is a proxy of some sort"),
 
     JS_FN_HELP("dumpHeapComplete", DumpHeapComplete, 1, 0,
-"dumpHeapComplete([filename])",
-"  Dump reachable and unreachable objects to a file."),
+"dumpHeapComplete(['collectNurseryBeforeDump'], [filename])",
+"  Dump reachable and unreachable objects to the named file, or to stdout.  If\n"
+"  'collectNurseryBeforeDump' is specified, a minor GC is performed first,\n"
+"  otherwise objects in the nursery are ignored."),
 
     JS_FN_HELP("terminate", Terminate, 0, 0,
 "terminate()",
 "  Terminate JavaScript execution, as if we had run out of\n"
 "  memory or been terminated by the slow script dialog."),
 
     JS_FN_HELP("enableSPSProfilingAssertions", EnableSPSProfilingAssertions, 1, 0,
 "enableSPSProfilingAssertions(slow)",
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-913224.js
@@ -0,0 +1,1 @@
+dumpHeapComplete();
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -748,36 +748,47 @@ DumpHeapVisitCell(JSRuntime *rt, void *d
     JS_GetTraceThingInfo(cellDesc, sizeof(cellDesc), dtrc, thing, traceKind, true);
     fprintf(dtrc->output, "%p %c %s\n", thing, MarkDescriptor(thing), cellDesc);
     JS_TraceChildren(dtrc, thing, traceKind);
 }
 
 static void
 DumpHeapVisitChild(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
+    if (gc::IsInsideNursery(trc->runtime, *thingp))
+        return;
+
     JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
     char buffer[1024];
     fprintf(dtrc->output, "> %p %c %s\n", *thingp, MarkDescriptor(*thingp),
             JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
 }
 
 static void
 DumpHeapVisitRoot(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
+    if (gc::IsInsideNursery(trc->runtime, *thingp))
+        return;
+
     JSDumpHeapTracer *dtrc = static_cast<JSDumpHeapTracer *>(trc);
     char buffer[1024];
     fprintf(dtrc->output, "%p %c %s\n", *thingp, MarkDescriptor(*thingp),
             JS_GetTraceEdgeName(dtrc, buffer, sizeof(buffer)));
 }
 
 void
-js::DumpHeapComplete(JSRuntime *rt, FILE *fp)
+js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour)
 {
     JSDumpHeapTracer dtrc(fp);
 
+#ifdef JSGC_GENERATIONAL
+    if (nurseryBehaviour == js::CollectNurseryBeforeDump)
+        MinorGC(rt, JS::gcreason::API);
+#endif
+
     JS_TracerInit(&dtrc, rt, DumpHeapVisitRoot);
     dtrc.eagerlyTraceWeakMaps = TraceWeakMapKeysValues;
     TraceRuntime(&dtrc);
 
     fprintf(dtrc.output, "==========\n");
 
     JS_TracerInit(&dtrc, rt, DumpHeapVisitChild);
     IterateZonesCompartmentsArenasCells(rt, &dtrc,
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -250,22 +250,27 @@ GetContextZone(const JSContext *cx)
 }
 
 extern JS_FRIEND_API(JS::Zone *)
 GetCompartmentZone(JSCompartment *comp);
 
 typedef bool
 (* PreserveWrapperCallback)(JSContext *cx, JSObject *obj);
 
+typedef enum  {
+    CollectNurseryBeforeDump,
+    IgnoreNurseryObjects
+} DumpHeapNurseryBehaviour;
+
  /*
   * Dump the complete object graph of heap-allocated things.
   * fp is the file for the dump output.
   */
 extern JS_FRIEND_API(void)
-DumpHeapComplete(JSRuntime *rt, FILE *fp);
+DumpHeapComplete(JSRuntime *rt, FILE *fp, DumpHeapNurseryBehaviour nurseryBehaviour);
 
 #ifdef JS_OLD_GETTER_SETTER_METHODS
 JS_FRIEND_API(bool) obj_defineGetter(JSContext *cx, unsigned argc, JS::Value *vp);
 JS_FRIEND_API(bool) obj_defineSetter(JSContext *cx, unsigned argc, JS::Value *vp);
 #endif
 
 extern JS_FRIEND_API(bool)
 IsSystemCompartment(JSCompartment *comp);
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -963,17 +963,17 @@ void
 CycleCollectedJSRuntime::DeferredFinalize(nsISupports* aSupports)
 {
   mDeferredSupports.AppendElement(aSupports);
 }
 
 void
 CycleCollectedJSRuntime::DumpJSHeap(FILE* file)
 {
-  js::DumpHeapComplete(Runtime(), file);
+  js::DumpHeapComplete(Runtime(), file, js::CollectNurseryBeforeDump);
 }
 
 
 bool
 ReleaseSliceNow(uint32_t aSlice, void* aData)
 {
   MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with slice == 0");
   nsTArray<nsISupports*>* items = static_cast<nsTArray<nsISupports*>*>(aData);