Bug 1197970 - Expose the GC cycle's number through Debugger.Memory's onGarbageCollection hook. r=sfink
authorNick Fitzgerald <fitzgen@gmail.com>
Wed, 26 Aug 2015 10:13:00 -0400
changeset 259549 312e50ab7cd29ace443d5134dd64b5aa6ec512b1
parent 259548 a819698325b239c059988f13e0ddad8d11804269
child 259550 f9edb5fe8fb982f13b2c81034b4dbba628a69f33
push id29283
push userryanvm@gmail.com
push dateThu, 27 Aug 2015 15:43:21 +0000
treeherdermozilla-central@638ac65d9b3f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1197970
milestone43.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 1197970 - Expose the GC cycle's number through Debugger.Memory's onGarbageCollection hook. r=sfink
js/src/doc/Debugger/Debugger.Memory.md
js/src/vm/CommonPropertyNames.h
js/src/vm/Debugger.cpp
js/xpconnect/tests/unit/test_onGarbageCollection-05.js
js/xpconnect/tests/unit/xpcshell.ini
--- a/js/src/doc/Debugger/Debugger.Memory.md
+++ b/js/src/doc/Debugger/Debugger.Memory.md
@@ -219,16 +219,20 @@ compartment.
         string describing the reason it determined the full GC was necessary.
         Otherwise, `null` is returned. Known values include the following:
 
         * "GC mode"
         * "malloc bytes trigger"
         * "allocation trigger"
         * "requested"
 
+    `gcCycleNumber`
+    :   The GC cycle's "number". Does not correspond to the number
+        of GC cycles that have run, but is guaranteed to be monotonically
+        increasing.
 
 Function Properties of the `Debugger.Memory.prototype` Object
 -------------------------------------------------------------
 
 <code id='drain-alloc-log'>drainAllocationsLog()</code>
 :   When `trackingAllocationSites` is `true`, this method returns an array of
     recent `Object` allocations within the set of debuggees. *Recent* is
     defined as the `maxAllocationsLogLength` most recent `Object` allocations
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -87,16 +87,17 @@
     macro(float32x4, float32x4, "Float32x4") \
     macro(float64, float64, "float64") \
     macro(float64x2, float64x2, "Float64x2") \
     macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
     macro(forEach, forEach, "forEach") \
     macro(format, format, "format") \
     macro(frame, frame, "frame") \
     macro(from, from, "from") \
+    macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
     macro(get, get, "get") \
     macro(getInternals, getInternals, "getInternals") \
     macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
     macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
     macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
     macro(global, global, "global") \
     macro(Handle, Handle, "Handle") \
     macro(has, has, "has") \
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8177,19 +8177,21 @@ DefineStringProperty(JSContext* cx, Hand
     }
     return DefineProperty(cx, obj, propName, val);
 }
 
 JSObject*
 GarbageCollectionEvent::toJSObject(JSContext* cx) const
 {
     RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
+    RootedValue gcCycleNumberVal(cx, NumberValue(majorGCNumber_));
     if (!obj ||
         !DefineStringProperty(cx, obj, cx->names().nonincrementalReason, nonincrementalReason) ||
-        !DefineStringProperty(cx, obj, cx->names().reason, reason))
+        !DefineStringProperty(cx, obj, cx->names().reason, reason) ||
+        !DefineProperty(cx, obj, cx->names().gcCycleNumber, gcCycleNumberVal))
     {
         return nullptr;
     }
 
     RootedArrayObject slicesArray(cx, NewDenseEmptyArray(cx));
     if (!slicesArray)
         return nullptr;
 
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_onGarbageCollection-05.js
@@ -0,0 +1,37 @@
+// Test that the onGarbageCollection hook reports its gc cycle's number (aka the
+// major GC number) and that it is monotonically increasing.
+
+const root = newGlobal();
+const dbg = new Debugger();
+const wrappedRoot = dbg.addDebuggee(root)
+
+function run_test() {
+  do_test_pending();
+
+  let numFired = 0;
+  let lastGCCycleNumber = undefined;
+
+  (function loop() {
+    if (numFired == 10) {
+      dbg.memory.onGarbageCollection = undefined;
+      dbg.enabled = false;
+      return void do_test_finished();
+    }
+
+    dbg.memory.onGarbageCollection = data => {
+      print("onGarbageCollection: " + uneval(data));
+
+      if (numFired != 0) {
+        equal(typeof lastGCCycleNumber, "number");
+        equal(data.gcCycleNumber - lastGCCycleNumber, 1);
+      }
+
+      numFired++;
+      lastGCCycleNumber = data.gcCycleNumber;
+
+      executeSoon(loop);
+    };
+
+    root.eval("gc(this)");
+  }());
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -75,16 +75,18 @@ support-files =
 [test_onGarbageCollection-01.js]
 head = head_ongc.js
 [test_onGarbageCollection-02.js]
 head = head_ongc.js
 [test_onGarbageCollection-03.js]
 head = head_ongc.js
 [test_onGarbageCollection-04.js]
 head = head_ongc.js
+[test_onGarbageCollection-05.js]
+head = head_ongc.js
 [test_reflect_parse.js]
 [test_localeCompare.js]
 # Bug 676965: test fails consistently on Android
 fail-if = os == "android"
 [test_recursive_import.js]
 [test_xpcomutils.js]
 [test_unload.js]
 [test_attributes.js]