Bug 1150253 - Part 2: Gecko should provide a callback for SpiderMonkey to
authorNick Fitzgerald <fitzgen@gmail.com>
Wed, 22 Apr 2015 09:43:02 -0700
changeset 240538 9ef1368b7c9fbaedafb228581005a3d43370366c
parent 240537 dcf12f5e9a96b02900b5cea3a2793b06b5d28c06
child 240539 feeed2f82c6f3a4d4643487912d6f0b7b51a37e0
push id58853
push usernfitzgerald@mozilla.com
push dateWed, 22 Apr 2015 16:43:21 +0000
treeherdermozilla-inbound@feeed2f82c6f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1150253
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 1150253 - Part 2: Gecko should provide a callback for SpiderMonkey to enqueue the onGarbageCollection hook runnable; r=mccr8
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/CycleCollectedJSRuntime.h
xpcom/base/DebuggerOnGCRunnable.cpp
xpcom/base/DebuggerOnGCRunnable.h
xpcom/base/moz.build
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -55,16 +55,17 @@
 // traversed.
 
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include <algorithm>
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/DebuggerOnGCRunnable.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "jsprf.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
 #include "nsJSUtils.h"
@@ -461,32 +462,34 @@ NoteJSChildGrayWrapperShim(void* aData, 
 static const JSZoneParticipant sJSZoneCycleCollectorGlobal;
 
 CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSRuntime* aParentRuntime,
                                                  uint32_t aMaxBytes,
                                                  uint32_t aMaxNurseryBytes)
   : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal)
   , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal)
   , mJSRuntime(nullptr)
+  , mPrevGCSliceCallback(nullptr)
   , mJSHolders(256)
   , mOutOfMemoryState(OOMState::OK)
   , mLargeAllocationFailureState(OOMState::OK)
 {
   mozilla::dom::InitScriptSettings();
 
   mJSRuntime = JS_NewRuntime(aMaxBytes, aMaxNurseryBytes, aParentRuntime);
   if (!mJSRuntime) {
     MOZ_CRASH();
   }
 
   if (!JS_AddExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this)) {
     MOZ_CRASH();
   }
   JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
   JS_SetGCCallback(mJSRuntime, GCCallback, this);
+  mPrevGCSliceCallback = JS::SetGCSliceCallback(mJSRuntime, GCSliceCallback);
   JS::SetOutOfMemoryCallback(mJSRuntime, OutOfMemoryCallback, this);
   JS::SetLargeAllocationFailureCallback(mJSRuntime,
                                         LargeAllocationFailureCallback, this);
   JS_SetContextCallback(mJSRuntime, ContextCallback, this);
   JS_SetDestroyZoneCallback(mJSRuntime, XPCStringConvert::FreeZoneCache);
   JS_SetSweepZoneCallback(mJSRuntime, XPCStringConvert::ClearZoneCache);
 
   static js::DOMCallbacks DOMcallbacks = {
@@ -741,16 +744,33 @@ CycleCollectedJSRuntime::GCCallback(JSRu
   CycleCollectedJSRuntime* self = static_cast<CycleCollectedJSRuntime*>(aData);
 
   MOZ_ASSERT(aRuntime == self->Runtime());
 
   self->OnGC(aStatus);
 }
 
 /* static */ void
+CycleCollectedJSRuntime::GCSliceCallback(JSRuntime* aRuntime,
+                                         JS::GCProgress aProgress,
+                                         const JS::GCDescription& aDesc)
+{
+  CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
+  MOZ_ASSERT(self->Runtime() == aRuntime);
+
+  if (aProgress == JS::GC_CYCLE_END) {
+    NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aRuntime, aDesc)));
+  }
+
+  if (self->mPrevGCSliceCallback) {
+    self->mPrevGCSliceCallback(aRuntime, aProgress, aDesc);
+  }
+}
+
+/* static */ void
 CycleCollectedJSRuntime::OutOfMemoryCallback(JSContext* aContext,
                                              void* aData)
 {
   CycleCollectedJSRuntime* self = static_cast<CycleCollectedJSRuntime*>(aData);
 
   MOZ_ASSERT(JS_GetRuntime(aContext) == self->Runtime());
 
   self->OnOutOfMemory();
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -189,16 +189,18 @@ private:
   static void
   TraverseObjectShim(void* aData, JS::GCCellPtr aThing);
 
   void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb);
 
   static void TraceBlackJS(JSTracer* aTracer, void* aData);
   static void TraceGrayJS(JSTracer* aTracer, void* aData);
   static void GCCallback(JSRuntime* aRuntime, JSGCStatus aStatus, void* aData);
+  static void GCSliceCallback(JSRuntime* aRuntime, JS::GCProgress aProgress,
+                              const JS::GCDescription& aDesc);
   static void OutOfMemoryCallback(JSContext* aContext, void* aData);
   static void LargeAllocationFailureCallback(void* aData);
   static bool ContextCallback(JSContext* aCx, unsigned aOperation,
                               void* aData);
 
   virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
   void TraceNativeGrayRoots(JSTracer* aTracer);
 
@@ -303,16 +305,18 @@ public:
 
 private:
   JSGCThingParticipant mGCThingCycleCollectorGlobal;
 
   JSZoneParticipant mJSZoneCycleCollectorGlobal;
 
   JSRuntime* mJSRuntime;
 
+  JS::GCSliceCallback mPrevGCSliceCallback;
+
   nsDataHashtable<nsPtrHashKey<void>, nsScriptObjectTracer*> mJSHolders;
 
   typedef nsDataHashtable<nsFuncPtrHashKey<DeferredFinalizeFunction>, void*>
     DeferredFinalizerTable;
   DeferredFinalizerTable mDeferredFinalizerTable;
 
   nsRefPtr<IncrementalFinalizeRunnable> mFinalizeRunnable;
 
new file mode 100644
--- /dev/null
+++ b/xpcom/base/DebuggerOnGCRunnable.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/DebuggerOnGCRunnable.h"
+
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
+#include "mozilla/Move.h"
+#include "js/Debug.h"
+
+namespace mozilla {
+
+/* static */ NS_METHOD
+DebuggerOnGCRunnable::Enqueue(JSRuntime* aRt, const JS::GCDescription& aDesc)
+{
+  auto gcEvent = aDesc.toGCEvent(aRt);
+  if (!gcEvent) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  nsRefPtr<DebuggerOnGCRunnable> runOnGC =
+    new DebuggerOnGCRunnable(Move(gcEvent));
+  return NS_DispatchToCurrentThread(runOnGC);
+}
+
+NS_IMETHODIMP
+DebuggerOnGCRunnable::Run()
+{
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  if (!JS::dbg::FireOnGarbageCollectionHook(jsapi.cx(), Move(mGCData))) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DebuggerOnGCRunnable::Cancel()
+{
+  mGCData = nullptr;
+  return NS_OK;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/base/DebuggerOnGCRunnable.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozilla_DebuggerOnGCRunnable_h
+#define mozilla_DebuggerOnGCRunnable_h
+
+#include "nsThreadUtils.h"
+#include "js/GCAPI.h"
+#include "mozilla/Move.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla {
+
+// Runnable to fire the SpiderMonkey Debugger API's onGarbageCollection hook.
+class DebuggerOnGCRunnable : public nsCancelableRunnable
+{
+  JS::dbg::GarbageCollectionEvent::Ptr mGCData;
+
+  explicit DebuggerOnGCRunnable(JS::dbg::GarbageCollectionEvent::Ptr&& aGCData)
+    : mGCData(Move(aGCData))
+  { }
+
+public:
+  static NS_METHOD Enqueue(JSRuntime* aRt, const JS::GCDescription& aDesc);
+
+  NS_DECL_NSIRUNNABLE
+  NS_DECL_NSICANCELABLERUNNABLE
+};
+
+} // namespace mozilla
+
+#endif // ifdef mozilla_dom_DebuggerOnGCRunnable_h
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -72,16 +72,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         SOURCES += ['pure_api.c']
 
 EXPORTS.mozilla += [
     'AvailableMemoryTracker.h',
     'ClearOnShutdown.h',
     'CountingAllocatorBase.h',
     'CycleCollectedJSRuntime.h',
     'Debug.h',
+    'DebuggerOnGCRunnable.h',
     'DeferredFinalize.h',
     'ErrorNames.h',
     'HoldDropJSObjects.h',
     'LinuxUtils.h',
     'nsMemoryInfoDumper.h',
     'StackWalk.h',
     'StaticMutex.h',
     'StaticPtr.h',
@@ -96,16 +97,17 @@ SOURCES += [
 ]
 SOURCES['nsDebugImpl.cpp'].no_pgo = True
 
 UNIFIED_SOURCES += [
     'AvailableMemoryTracker.cpp',
     'ClearOnShutdown.cpp',
     'CycleCollectedJSRuntime.cpp',
     'Debug.cpp',
+    'DebuggerOnGCRunnable.cpp',
     'DeferredFinalize.cpp',
     'ErrorNames.cpp',
     'HoldDropJSObjects.cpp',
     'nsConsoleMessage.cpp',
     'nsConsoleService.cpp',
     'nsCycleCollector.cpp',
     'nsDumpUtils.cpp',
     'nsErrorService.cpp',