Backed out changeset 50c03319c341 (bug 1246091) for mochitest failures. r=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 11 Mar 2016 20:16:19 +0100
changeset 339599 3f3abdbf2d06fef628c8ddc71624de3acb801c23
parent 339598 e3dcb77f780141d9e035bb460a982448ba7fb0b0
child 339600 ce018c5ee5c15e76c640f0c0e2414ab7c6a04657
push id12762
push userbmo:rail@mozilla.com
push dateFri, 11 Mar 2016 19:47:45 +0000
reviewersbackout
bugs1246091
milestone48.0a1
backs out50c03319c341910196103c4451f17299eb144313
Backed out changeset 50c03319c341 (bug 1246091) for mochitest failures. r=backout
dom/base/Console.cpp
dom/base/Console.h
dom/base/nsGlobalWindow.cpp
dom/bindings/Bindings.conf
dom/webidl/WorkerDebuggerGlobalScope.webidl
dom/webidl/WorkerGlobalScope.webidl
dom/workers/RuntimeService.cpp
dom/workers/RuntimeService.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/WorkerScope.h
dom/workers/test/WorkerDebugger.console_childWorker.js
dom/workers/test/WorkerDebugger.console_debugger.js
dom/workers/test/WorkerDebugger.console_worker.js
dom/workers/test/chrome.ini
dom/workers/test/test_WorkerDebugger_console.xul
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/ConsoleBinding.h"
 
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/File.h"
-#include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Maybe.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDocument.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsGlobalWindow.h"
 #include "nsJSUtils.h"
@@ -51,19 +50,16 @@
 // The maximum stacktrace depth when populating the stacktrace array used for
 // console.trace().
 #define DEFAULT_MAX_STACKTRACE_DEPTH 200
 
 // This tags are used in the Structured Clone Algorithm to move js values from
 // worker thread to main thread
 #define CONSOLE_TAG_BLOB   JS_SCTAG_USER_MIN
 
-// This value is taken from ConsoleAPIStorage.js
-#define STORAGE_MAX_EVENTS 200
-
 using namespace mozilla::dom::exceptions;
 using namespace mozilla::dom::workers;
 
 namespace mozilla {
 namespace dom {
 
 struct
 ConsoleStructuredCloneData
@@ -94,42 +90,38 @@ public:
     , mStopTimerStatus(false)
     , mCountValue(MAX_PAGE_COUNTERS)
     , mIDType(eUnknown)
     , mOuterIDNumber(0)
     , mInnerIDNumber(0)
 #ifdef DEBUG
     , mOwningThread(PR_GetCurrentThread())
 #endif
-  {}
+  { }
 
-  bool
+  void
   Initialize(JSContext* aCx, Console::MethodName aName,
              const nsAString& aString,
              const Sequence<JS::Value>& aArguments,
              Console* aConsole)
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(aConsole);
 
-    // We must be registered before doing any JS operation otherwise it can
-    // happen that mCopiedArguments are not correctly traced.
-    aConsole->StoreCallData(this);
+    aConsole->RegisterConsoleCallData(this);
+    mConsole = aConsole;
 
     mMethodName = aName;
     mMethodString = aString;
 
     for (uint32_t i = 0; i < aArguments.Length(); ++i) {
-      if (NS_WARN_IF(!mCopiedArguments.AppendElement(aArguments[i]))) {
-        aConsole->UnstoreCallData(this);
-        return false;
+      if (!mCopiedArguments.AppendElement(aArguments[i])) {
+        return;
       }
     }
-
-    return true;
   }
 
   void
   SetIDs(uint64_t aOuterID, uint64_t aInnerID)
   {
     MOZ_ASSERT(mIDType == eUnknown);
 
     mOuterIDNumber = aOuterID;
@@ -142,29 +134,26 @@ public:
   {
     MOZ_ASSERT(mIDType == eUnknown);
 
     mOuterIDString = aOuterID;
     mInnerIDString = aInnerID;
     mIDType = eString;
   }
 
-  bool
-  PopulateSequenceArguments(Sequence<JS::Value>& aSequence) const
+  void
+  CleanupJSObjects()
   {
     AssertIsOnOwningThread();
+    mCopiedArguments.Clear();
 
-    for (uint32_t i = 0; i < mCopiedArguments.Length(); ++i) {
-      if (NS_WARN_IF(!aSequence.AppendElement(mCopiedArguments[i],
-                                              fallible))) {
-        return false;
-      }
+    if (mConsole) {
+      mConsole->UnregisterConsoleCallData(this);
+      mConsole = nullptr;
     }
-
-    return true;
   }
 
   void
   Trace(const TraceCallbacks& aCallbacks, void* aClosure)
   {
     AssertIsOnOwningThread();
 
     ConsoleCallData* tmp = this;
@@ -190,35 +179,35 @@ public:
   int64_t mTimeStamp;
 
   // These values are set in the owning thread and they contain the timestamp of
   // when the new timer has started, the name of it and the status of the
   // creation of it. If status is false, something went wrong. User
   // DOMHighResTimeStamp instead mozilla::TimeStamp because we use
   // monotonicTimer from Performance.now();
   // They will be set on the owning thread and never touched again on that
-  // thread. They will be used in order to create a ConsoleTimerStart dictionary
-  // when console.time() is used.
+  // thread. They will be used on the main-thread in order to create a
+  // ConsoleTimerStart dictionary when console.time() is used.
   DOMHighResTimeStamp mStartTimerValue;
   nsString mStartTimerLabel;
   bool mStartTimerStatus;
 
   // These values are set in the owning thread and they contain the duration,
   // the name and the status of the StopTimer method. If status is false,
   // something went wrong. They will be set on the owning thread and never
-  // touched again on that thread. They will be used in order to create a
-  // ConsoleTimerEnd dictionary. This members are set when
+  // touched again on that thread. They will be used on the main-thread in order
+  // to create a ConsoleTimerEnd dictionary. This members are set when
   // console.timeEnd() is called.
   double mStopTimerDuration;
   nsString mStopTimerLabel;
   bool mStopTimerStatus;
 
   // These 2 values are set by IncreaseCounter on the owning thread and they are
-  // used CreateCounterValue. These members are set when console.count() is
-  // called.
+  // used on the main-thread by CreateCounterValue. These members are set when
+  // console.count() is called.
   nsString mCountLabel;
   uint32_t mCountValue;
 
   // The concept of outerID and innerID is misleading because when a
   // ConsoleCallData is created from a window, these are the window IDs, but
   // when the object is created from a SharedWorker, a ServiceWorker or a
   // subworker of a ChromeWorker these IDs are the type of worker and the
   // filename of the callee.
@@ -242,46 +231,28 @@ public:
   // 1)  mTopStackFrame is initialized whenever we have any JS on the stack
   // 2)  mReifiedStack is initialized if we're created in a worker.
   // 3)  mStack is set (possibly to null if there is no JS on the stack) if
   //     we're created on main thread.
   Maybe<ConsoleStackEntry> mTopStackFrame;
   Maybe<nsTArray<ConsoleStackEntry>> mReifiedStack;
   nsCOMPtr<nsIStackFrame> mStack;
 
-  // mStatus is about the lifetime of this object. Console must take care of
-  // keep it alive or not following this enumeration.
-  enum {
-    // If the object is created but it is owned by some runnable, this is its
-    // status. It can be deleted at any time.
-    eUnused,
-
-    // When a runnable takes ownership of a ConsoleCallData and send it to
-    // different thread, this is its status. Console cannot delete it at this
-    // time.
-    eInUse,
-
-    // When a runnable owns this ConsoleCallData, we can't delete it directly.
-    // instead, we mark it with this new status and we move it in
-    // mCallDataStoragePending list in order to keep it alive an trace it
-    // correctly. Once the runnable finishs its task, it will delete this object
-    // calling ReleaseCallData().
-    eToBeDeleted
-  } mStatus;
-
 #ifdef DEBUG
   PRThread* mOwningThread;
 #endif
 
 private:
   ~ConsoleCallData()
   {
     AssertIsOnOwningThread();
-    MOZ_ASSERT(mStatus != eInUse);
+    CleanupJSObjects();
   }
+
+  RefPtr<Console> mConsole;
 };
 
 // This class is used to clear any exception at the end of this method.
 class ClearException
 {
 public:
   explicit ClearException(JSContext* aCx)
     : mCx(aCx)
@@ -318,17 +289,17 @@ public:
 
   bool
   Dispatch(JS::Handle<JSObject*> aGlobal)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     JSContext* cx = mWorkerPrivate->GetJSContext();
 
-    if (NS_WARN_IF(!PreDispatch(cx, aGlobal))) {
+    if (!PreDispatch(cx, aGlobal)) {
       return false;
     }
 
     if (NS_WARN_IF(!mWorkerPrivate->AddFeature(this))) {
       return false;
     }
 
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
@@ -338,18 +309,17 @@ public:
   virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
   {
     // We don't care about the notification. We just want to keep the
     // mWorkerPrivate alive.
     return true;
   }
 
 private:
-  NS_IMETHOD
-  Run() override
+  NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     // Walk up to our containing page
     WorkerPrivate* wp = mWorkerPrivate;
     while (wp->GetParent()) {
       wp = wp->GetParent();
     }
@@ -496,32 +466,32 @@ protected:
 
   virtual bool CustomWriteHandler(JSContext* aCx,
                                   JSStructuredCloneWriter* aWriter,
                                   JS::Handle<JSObject*> aObj) override
   {
     RefPtr<Blob> blob;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
         blob->Impl()->MayBeClonedToOtherThreads()) {
-      if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB,
-                                         mClonedData.mBlobs.Length()))) {
+      if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB,
+                              mClonedData.mBlobs.Length())) {
         return false;
       }
 
       mClonedData.mBlobs.AppendElement(blob->Impl());
       return true;
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
     JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
-    if (NS_WARN_IF(!jsString)) {
+    if (!jsString) {
       return false;
     }
 
-    if (NS_WARN_IF(!JS_WriteString(aWriter, jsString))) {
+    if (!JS_WriteString(aWriter, jsString)) {
       return false;
     }
 
     return true;
   }
 
   WorkerPrivate* mWorkerPrivate;
 
@@ -535,60 +505,57 @@ protected:
 // the main-thread.
 class ConsoleCallDataRunnable final : public ConsoleRunnable
 {
 public:
   ConsoleCallDataRunnable(Console* aConsole,
                           ConsoleCallData* aCallData)
     : ConsoleRunnable(aConsole)
     , mCallData(aCallData)
-  {
-    MOZ_ASSERT(aCallData);
-    mCallData->mStatus = ConsoleCallData::eInUse;
-  }
+  { }
 
 private:
   bool
   PreDispatch(JSContext* aCx, JS::Handle<JSObject*> aGlobal) override
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
-    mCallData->AssertIsOnOwningThread();
 
     ClearException ce(aCx);
     JSAutoCompartment ac(aCx, aGlobal);
 
     JS::Rooted<JSObject*> arguments(aCx,
       JS_NewArrayObject(aCx, mCallData->mCopiedArguments.Length()));
-    if (NS_WARN_IF(!arguments)) {
+    if (!arguments) {
       return false;
     }
 
     JS::Rooted<JS::Value> arg(aCx);
     for (uint32_t i = 0; i < mCallData->mCopiedArguments.Length(); ++i) {
       arg = mCallData->mCopiedArguments[i];
-      if (NS_WARN_IF(!JS_DefineElement(aCx, arguments, i, arg,
-                                       JSPROP_ENUMERATE))) {
+      if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) {
         return false;
       }
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
-    if (NS_WARN_IF(!Write(aCx, value))) {
+    if (!Write(aCx, value)) {
       return false;
     }
 
+    mCallData->CleanupJSObjects();
     return true;
   }
 
   void
   RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
              nsPIDOMWindowInner* aInnerWindow) override
   {
     AssertIsOnMainThread();
+    MOZ_ASSERT(mCallData->mCopiedArguments.IsEmpty());
 
     // The windows have to run in parallel.
     MOZ_ASSERT(!!aOuterWindow == !!aInnerWindow);
 
     if (aOuterWindow) {
       mCallData->SetIDs(aOuterWindow->WindowID(), aInnerWindow->WindowID());
     } else {
       ConsoleStackEntry frame;
@@ -618,25 +585,16 @@ private:
     ProcessCallData(aCx);
 
     mClonedData.mParent = nullptr;
   }
 
   virtual void
   ReleaseData() override
   {
-    mConsole->AssertIsOnOwningThread();
-
-    if (mCallData->mStatus == ConsoleCallData::eToBeDeleted) {
-      mConsole->ReleaseCallData(mCallData);
-    } else {
-      MOZ_ASSERT(mCallData->mStatus == ConsoleCallData::eInUse);
-      mCallData->mStatus = ConsoleCallData::eUnused;
-    }
-
     mCallData = nullptr;
   }
 
   void
   ProcessCallData(JSContext* aCx)
   {
     AssertIsOnMainThread();
 
@@ -673,20 +631,17 @@ private:
 
     MOZ_ASSERT(values.Length() == length);
 
     JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
 
     mConsole->ProcessCallData(mCallData, global, values);
   }
 
-  // We don't have to keep this object alive because this runnable is holding a
-  // reference of the Console object and this CallData is kept alive by that
-  // Console object.
-  ConsoleCallData* MOZ_NON_OWNING_REF mCallData;
+  RefPtr<ConsoleCallData> mCallData;
 };
 
 // This runnable calls ProfileMethod() on the console on the main-thread.
 class ConsoleProfileRunnable final : public ConsoleRunnable
 {
 public:
   ConsoleProfileRunnable(Console* aConsole, const nsAString& aAction,
                          const Sequence<JS::Value>& aArguments)
@@ -699,40 +654,39 @@ public:
 
 private:
   bool
   PreDispatch(JSContext* aCx, JS::Handle<JSObject*> aGlobal) override
   {
     ClearException ce(aCx);
 
     JS::Rooted<JSObject*> global(aCx, aGlobal);
-    if (NS_WARN_IF(!global)) {
+    if (!global) {
       return false;
     }
 
     JSAutoCompartment ac(aCx, global);
 
     JS::Rooted<JSObject*> arguments(aCx,
       JS_NewArrayObject(aCx, mArguments.Length()));
-    if (NS_WARN_IF(!arguments)) {
+    if (!arguments) {
       return false;
     }
 
     JS::Rooted<JS::Value> arg(aCx);
     for (uint32_t i = 0; i < mArguments.Length(); ++i) {
       arg = mArguments[i];
-      if (NS_WARN_IF(!JS_DefineElement(aCx, arguments, i, arg,
-                                       JSPROP_ENUMERATE))) {
+      if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) {
         return false;
       }
     }
 
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
 
-    if (NS_WARN_IF(!Write(aCx, value))) {
+    if (!Write(aCx, value)) {
       return false;
     }
 
     return true;
   }
 
   void
   RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
@@ -793,190 +747,121 @@ private:
 NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
 
 // We don't need to traverse/unlink mStorage and mSandbox because they are not
 // CCed objects and they are only used on the main thread, even when this
 // Console object is used on workers.
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsoleEventHandler)
-  tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Console)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsoleEventHandler)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Console)
-  for (uint32_t i = 0; i < tmp->mCallDataStorage.Length(); ++i) {
-    tmp->mCallDataStorage[i]->Trace(aCallbacks, aClosure);
-  }
-
-  for (uint32_t i = 0; i < tmp->mCallDataStoragePending.Length(); ++i) {
-    tmp->mCallDataStoragePending[i]->Trace(aCallbacks, aClosure);
+  for (uint32_t i = 0; i < tmp->mConsoleCallDataArray.Length(); ++i) {
+    tmp->mConsoleCallDataArray[i]->Trace(aCallbacks, aClosure);
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Console)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Console)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Console)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
-/* static */ already_AddRefed<Console>
-Console::Create(nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
-{
-  RefPtr<Console> console = new Console(aWindow);
-  console->Initialize(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
-  return console.forget();
-}
-
 Console::Console(nsPIDOMWindowInner* aWindow)
   : mWindow(aWindow)
 #ifdef DEBUG
   , mOwningThread(PR_GetCurrentThread())
 #endif
   , mOuterID(0)
   , mInnerID(0)
-  , mStatus(eUnknown)
 {
   if (mWindow) {
     MOZ_ASSERT(mWindow->IsInnerWindow());
     mInnerID = mWindow->WindowID();
 
     // Without outerwindow any console message coming from this object will not
     // shown in the devtools webconsole. But this should be fine because
     // probably we are shutting down, or the window is CCed/GCed.
     nsPIDOMWindowOuter* outerWindow = mWindow->GetOuterWindow();
     if (outerWindow) {
       mOuterID = outerWindow->WindowID();
     }
   }
-}
-
-Console::~Console()
-{
-  AssertIsOnOwningThread();
-  Shutdown();
-}
-
-void
-Console::Initialize(ErrorResult& aRv)
-{
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eUnknown);
-
-  mStatus = eInitialized;
 
   if (NS_IsMainThread()) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (NS_WARN_IF(!obs)) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
-
-    aRv = obs->AddObserver(this, "inner-window-destroyed", true);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
-    }
-
-    aRv = obs->AddObserver(this, "memory-pressure", true);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
+    if (obs) {
+      obs->AddObserver(this, "inner-window-destroyed", true);
     }
   }
 
   mozilla::HoldJSObjects(this);
 }
 
-void
-Console::Shutdown()
+Console::~Console()
 {
   AssertIsOnOwningThread();
-
-  if (mStatus == eUnknown || mStatus == eShuttingDown) {
-    return;
-  }
+  MOZ_ASSERT(mConsoleCallDataArray.IsEmpty());
 
-  if (NS_IsMainThread()) {
-    nsCOMPtr<nsIObserverService> obs =
-      do_GetService("@mozilla.org/observer-service;1");
-    if (obs) {
-      obs->RemoveObserver(this, "inner-window-destroyed");
-      obs->RemoveObserver(this, "memory-pressure");
-    }
-  } else {
+  if (!NS_IsMainThread()) {
     if (mStorage) {
       NS_ReleaseOnMainThread(mStorage.forget());
     }
 
     if (mSandbox) {
       NS_ReleaseOnMainThread(mSandbox.forget());
     }
   }
 
-  mStatus = eShuttingDown;
-
-  mTimerRegistry.Clear();
-
-  mCallDataStorage.Clear();
-  mCallDataStoragePending.Clear();
-
   mozilla::DropJSObjects(this);
 }
 
 NS_IMETHODIMP
 Console::Observe(nsISupports* aSubject, const char* aTopic,
                  const char16_t* aData)
 {
   AssertIsOnMainThread();
 
-  if (!strcmp(aTopic, "inner-window-destroyed")) {
-    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
-    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
-
-    uint64_t innerID;
-    nsresult rv = wrapper->GetData(&innerID);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (innerID == mInnerID) {
-      Shutdown();
-    }
-
+  if (strcmp(aTopic, "inner-window-destroyed")) {
     return NS_OK;
   }
 
-  if (!strcmp(aTopic, "memory-pressure")) {
-    ClearStorage();
-    return NS_OK;
+  nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
+  NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
+
+  uint64_t innerID;
+  nsresult rv = wrapper->GetData(&innerID);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (innerID == mInnerID) {
+    nsCOMPtr<nsIObserverService> obs =
+      do_GetService("@mozilla.org/observer-service;1");
+    if (obs) {
+      obs->RemoveObserver(this, "inner-window-destroyed");
+    }
+
+    mTimerRegistry.Clear();
   }
 
   return NS_OK;
 }
 
-void
-Console::ClearStorage()
-{
-  mCallDataStorage.Clear();
-}
-
 JSObject*
 Console::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ConsoleBinding::Wrap(aCx, this, aGivenProto);
 }
 
 #define METHOD(name, string)                                          \
   void                                                                \
@@ -992,17 +877,16 @@ METHOD(Error, "error")
 METHOD(Exception, "exception")
 METHOD(Debug, "debug")
 METHOD(Table, "table")
 
 void
 Console::Trace(JSContext* aCx)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   const Sequence<JS::Value> data;
   Method(aCx, MethodTrace, NS_LITERAL_STRING("trace"), data);
 }
 
 // Displays an interactive listing of all the properties of an object.
 METHOD(Dir, "dir");
 METHOD(Dirxml, "dirxml");
@@ -1010,84 +894,75 @@ METHOD(Dirxml, "dirxml");
 METHOD(Group, "group")
 METHOD(GroupCollapsed, "groupCollapsed")
 METHOD(GroupEnd, "groupEnd")
 
 void
 Console::Time(JSContext* aCx, const JS::Handle<JS::Value> aTime)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
     return;
   }
 
   Method(aCx, MethodTime, NS_LITERAL_STRING("time"), data);
 }
 
 void
 Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (!aTime.isUndefined() && !data.AppendElement(aTime, fallible)) {
     return;
   }
 
   Method(aCx, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"), data);
 }
 
 void
 Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
   if (aData.isString() && !data.AppendElement(aData, fallible)) {
     return;
   }
 
   Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
 }
 
 void
 Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
-
   ProfileMethod(aCx, NS_LITERAL_STRING("profile"), aData);
 }
 
 void
 Console::ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
-
   ProfileMethod(aCx, NS_LITERAL_STRING("profileEnd"), aData);
 }
 
 void
 Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
                        const Sequence<JS::Value>& aData)
 {
-  MOZ_ASSERT(mStatus == eInitialized);
-
   if (!NS_IsMainThread()) {
     // Here we are in a worker thread.
     RefPtr<ConsoleProfileRunnable> runnable =
       new ConsoleProfileRunnable(this, aAction, aData);
 
     JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
     runnable->Dispatch(global);
     return;
@@ -1135,30 +1010,28 @@ Console::ProfileMethod(JSContext* aCx, c
   }
 }
 
 void
 Console::Assert(JSContext* aCx, bool aCondition,
                 const Sequence<JS::Value>& aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   if (!aCondition) {
     Method(aCx, MethodAssert, NS_LITERAL_STRING("assert"), aData);
   }
 }
 
 METHOD(Count, "count")
 
 void
 Console::NoopMethod()
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   // Nothing to do.
 }
 
 static
 nsresult
 StackFrameToStackEntry(nsIStackFrame* aStackFrame,
                        ConsoleStackEntry& aStackEntry,
@@ -1228,26 +1101,22 @@ ReifyStack(nsIStackFrame* aStack, nsTArr
 
 // Queue a call to a console method. See the CALL_DELAY constant.
 void
 Console::Method(JSContext* aCx, MethodName aMethodName,
                 const nsAString& aMethodString,
                 const Sequence<JS::Value>& aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(mStatus == eInitialized);
 
   RefPtr<ConsoleCallData> callData(new ConsoleCallData());
 
   ClearException ce(aCx);
 
-  if (NS_WARN_IF(!callData->Initialize(aCx, aMethodName, aMethodString,
-                                       aData, this))) {
-    return;
-  }
+  callData->Initialize(aCx, aMethodName, aMethodString, aData, this);
 
   if (mWindow) {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
     if (!webNav) {
       return;
     }
 
     nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
@@ -1392,28 +1261,19 @@ Console::Method(JSContext* aCx, MethodNa
                                             callData->mCountLabel);
   }
 
   JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
 
   if (NS_IsMainThread()) {
     callData->SetIDs(mOuterID, mInnerID);
     ProcessCallData(callData, global, aData);
-
-    // Just because we don't want to expose
-    // retrieveConsoleEvents/setConsoleEventHandler to main-thread, we can
-    // cleanup the mCallDataStorage:
-    UnstoreCallData(callData);
     return;
   }
 
-  // We do this only in workers for now.
-  NotifyHandler(aCx, global, aData, callData);
-
-  // Moving the ownership of callData to the runnable.
   RefPtr<ConsoleCallDataRunnable> runnable =
     new ConsoleCallDataRunnable(this, callData);
   runnable->Dispatch(global);
 }
 
 // We store information to lazily compute the stack in the reserved slots of
 // LazyStackGetter.  The first slot always stores a JS object: it's either the
 // JS wrapper of the nsIStackFrame or the actual reified stack representation.
@@ -1422,36 +1282,38 @@ Console::Method(JSContext* aCx, MethodNa
 enum {
   SLOT_STACKOBJ,
   SLOT_RAW_STACK
 };
 
 bool
 LazyStackGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
 {
+  AssertIsOnMainThread();
+
   JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
   JS::Rooted<JSObject*> callee(aCx, &args.callee());
 
   JS::Value v = js::GetFunctionNativeReserved(&args.callee(), SLOT_RAW_STACK);
   if (v.isUndefined()) {
     // Already reified.
     args.rval().set(js::GetFunctionNativeReserved(callee, SLOT_STACKOBJ));
     return true;
   }
 
   nsIStackFrame* stack = reinterpret_cast<nsIStackFrame*>(v.toPrivate());
   nsTArray<ConsoleStackEntry> reifiedStack;
   nsresult rv = ReifyStack(stack, reifiedStack);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_FAILED(rv)) {
     Throw(aCx, rv);
     return false;
   }
 
   JS::Rooted<JS::Value> stackVal(aCx);
-  if (NS_WARN_IF(!ToJSValue(aCx, reifiedStack, &stackVal))) {
+  if (!ToJSValue(aCx, reifiedStack, &stackVal)) {
     return false;
   }
 
   MOZ_ASSERT(stackVal.isObject());
 
   js::SetFunctionNativeReserved(callee, SLOT_STACKOBJ, stackVal);
   js::SetFunctionNativeReserved(callee, SLOT_RAW_STACK, JS::UndefinedValue());
 
@@ -1461,35 +1323,177 @@ LazyStackGetter(JSContext* aCx, unsigned
 
 void
 Console::ProcessCallData(ConsoleCallData* aData, JS::Handle<JSObject*> aGlobal,
                          const Sequence<JS::Value>& aArguments)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aData);
 
+  ConsoleStackEntry frame;
+  if (aData->mTopStackFrame) {
+    frame = *aData->mTopStackFrame;
+  }
+
   AutoSafeJSContext cx;
-  JS::Rooted<JS::Value> eventValue(cx);
+  ClearException ce(cx);
+  RootedDictionary<ConsoleEvent> event(cx);
+
+  JSAutoCompartment ac(cx, aGlobal);
+
+  event.mID.Construct();
+  event.mInnerID.Construct();
+
+  MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
+  if (aData->mIDType == ConsoleCallData::eString) {
+    event.mID.Value().SetAsString() = aData->mOuterIDString;
+    event.mInnerID.Value().SetAsString() = aData->mInnerIDString;
+  } else {
+    MOZ_ASSERT(aData->mIDType == ConsoleCallData::eNumber);
+    event.mID.Value().SetAsUnsignedLongLong() = aData->mOuterIDNumber;
+    event.mInnerID.Value().SetAsUnsignedLongLong() = aData->mInnerIDNumber;
+  }
+
+  event.mLevel = aData->mMethodString;
+  event.mFilename = frame.mFilename;
+
+  nsCOMPtr<nsIURI> filenameURI;
+  nsAutoCString pass;
+  if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(filenameURI), frame.mFilename)) &&
+      NS_SUCCEEDED(filenameURI->GetPassword(pass)) && !pass.IsEmpty()) {
+    nsCOMPtr<nsISensitiveInfoHiddenURI> safeURI = do_QueryInterface(filenameURI);
+    nsAutoCString spec;
+    if (safeURI &&
+        NS_SUCCEEDED(safeURI->GetSensitiveInfoHiddenSpec(spec))) {
+      CopyUTF8toUTF16(spec, event.mFilename);
+    }
+  }
+
+  event.mLineNumber = frame.mLineNumber;
+  event.mColumnNumber = frame.mColumnNumber;
+  event.mFunctionName = frame.mFunctionName;
+  event.mTimeStamp = aData->mTimeStamp;
+  event.mPrivate = aData->mPrivate;
+
+  switch (aData->mMethodName) {
+    case MethodLog:
+    case MethodInfo:
+    case MethodWarn:
+    case MethodError:
+    case MethodException:
+    case MethodDebug:
+    case MethodAssert:
+      event.mArguments.Construct();
+      event.mStyles.Construct();
+      if (!ProcessArguments(cx, aArguments, event.mArguments.Value(),
+                            event.mStyles.Value())) {
+        return;
+      }
+
+      break;
+
+    default:
+      event.mArguments.Construct();
+      if (!ArgumentsToValueList(aArguments, event.mArguments.Value())) {
+        return;
+      }
+  }
+
+  if (aData->mMethodName == MethodGroup ||
+      aData->mMethodName == MethodGroupCollapsed ||
+      aData->mMethodName == MethodGroupEnd) {
+    ComposeGroupName(cx, aArguments, event.mGroupName);
+  }
+
+  else if (aData->mMethodName == MethodTime && !aArguments.IsEmpty()) {
+    event.mTimer = CreateStartTimerValue(cx, aData->mStartTimerLabel,
+                                         aData->mStartTimerValue,
+                                         aData->mStartTimerStatus);
+  }
+
+  else if (aData->mMethodName == MethodTimeEnd && !aArguments.IsEmpty()) {
+    event.mTimer = CreateStopTimerValue(cx, aData->mStopTimerLabel,
+                                        aData->mStopTimerDuration,
+                                        aData->mStopTimerStatus);
+  }
+
+  else if (aData->mMethodName == MethodCount) {
+    event.mCounter = CreateCounterValue(cx, aData->mCountLabel,
+                                        aData->mCountValue);
+  }
 
   // We want to create a console event object and pass it to our
   // nsIConsoleAPIStorage implementation.  We want to define some accessor
   // properties on this object, and those will need to keep an nsIStackFrame
   // alive.  But nsIStackFrame cannot be wrapped in an untrusted scope.  And
   // further, passing untrusted objects to system code is likely to run afoul of
   // Object Xrays.  So we want to wrap in a system-principal scope here.  But
   // which one?  We could cheat and try to get the underlying JSObject* of
   // mStorage, but that's a bit fragile.  Instead, we just use the junk scope,
   // with explicit permission from the XPConnect module owner.  If you're
   // tempted to do that anywhere else, talk to said module owner first.
   JSAutoCompartment ac2(cx, xpc::PrivilegedJunkScope());
 
-  if (NS_WARN_IF(!PopulateEvent(cx, aGlobal, aArguments, &eventValue, aData))) {
+  JS::Rooted<JS::Value> eventValue(cx);
+  if (!ToJSValue(cx, event, &eventValue)) {
+    return;
+  }
+
+  JS::Rooted<JSObject*> eventObj(cx, &eventValue.toObject());
+  MOZ_ASSERT(eventObj);
+
+  if (!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventValue, JSPROP_ENUMERATE)) {
     return;
   }
 
+  if (ShouldIncludeStackTrace(aData->mMethodName)) {
+    // Now define the "stacktrace" property on eventObj.  There are two cases
+    // here.  Either we came from a worker and have a reified stack, or we want
+    // to define a getter that will lazily reify the stack.
+    if (aData->mReifiedStack) {
+      JS::Rooted<JS::Value> stacktrace(cx);
+      if (!ToJSValue(cx, *aData->mReifiedStack, &stacktrace) ||
+          !JS_DefineProperty(cx, eventObj, "stacktrace", stacktrace,
+                             JSPROP_ENUMERATE)) {
+        return;
+      }
+    } else {
+      JSFunction* fun = js::NewFunctionWithReserved(cx, LazyStackGetter, 0, 0,
+                                                    "stacktrace");
+      if (!fun) {
+        return;
+      }
+
+      JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
+
+      // We want to store our stack in the function and have it stay alive.  But
+      // we also need sane access to the C++ nsIStackFrame.  So store both a JS
+      // wrapper and the raw pointer: the former will keep the latter alive.
+      JS::Rooted<JS::Value> stackVal(cx);
+      nsresult rv = nsContentUtils::WrapNative(cx, aData->mStack,
+                                               &stackVal);
+      if (NS_FAILED(rv)) {
+        return;
+      }
+
+      js::SetFunctionNativeReserved(funObj, SLOT_STACKOBJ, stackVal);
+      js::SetFunctionNativeReserved(funObj, SLOT_RAW_STACK,
+                                    JS::PrivateValue(aData->mStack.get()));
+
+      if (!JS_DefineProperty(cx, eventObj, "stacktrace",
+                             JS::UndefinedHandleValue,
+                             JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER |
+                             JSPROP_SETTER,
+                             JS_DATA_TO_FUNC_PTR(JSNative, funObj.get()),
+                             nullptr)) {
+        return;
+      }
+    }
+  }
+
   if (!mStorage) {
     mStorage = do_GetService("@mozilla.org/consoleAPI-storage;1");
   }
 
   if (!mStorage) {
     NS_WARNING("Failed to get the ConsoleAPIStorage service.");
     return;
   }
@@ -1506,196 +1510,33 @@ Console::ProcessCallData(ConsoleCallData
     innerID.AppendInt(aData->mInnerIDNumber);
   }
 
   if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) {
     NS_WARNING("Failed to record a console event.");
   }
 }
 
-bool
-Console::PopulateEvent(JSContext* aCx,
-                       JS::Handle<JSObject*> aGlobal,
-                       const Sequence<JS::Value>& aArguments,
-                       JS::MutableHandle<JS::Value> aEventValue,
-                       ConsoleCallData* aData) const
-{
-  MOZ_ASSERT(aCx);
-  MOZ_ASSERT(aData);
-
-  ConsoleStackEntry frame;
-  if (aData->mTopStackFrame) {
-    frame = *aData->mTopStackFrame;
-  }
-
-  ClearException ce(aCx);
-  RootedDictionary<ConsoleEvent> event(aCx);
-
-  JSAutoCompartment ac(aCx, aGlobal);
-
-  event.mID.Construct();
-  event.mInnerID.Construct();
-
-  if (aData->mIDType == ConsoleCallData::eString) {
-    event.mID.Value().SetAsString() = aData->mOuterIDString;
-    event.mInnerID.Value().SetAsString() = aData->mInnerIDString;
-  } else if (aData->mIDType == ConsoleCallData::eNumber) {
-    event.mID.Value().SetAsUnsignedLongLong() = aData->mOuterIDNumber;
-    event.mInnerID.Value().SetAsUnsignedLongLong() = aData->mInnerIDNumber;
-  } else {
-    // aData->mIDType can be eUnknown when we dispatch notifications via
-    // mConsoleEventHandler.
-    event.mID.Value().SetAsUnsignedLongLong() = 0;
-    event.mInnerID.Value().SetAsUnsignedLongLong() = 0;
-  }
-
-  event.mLevel = aData->mMethodString;
-  event.mFilename = frame.mFilename;
-
-  nsCOMPtr<nsIURI> filenameURI;
-  nsAutoCString pass;
-  if (NS_IsMainThread() &&
-      NS_SUCCEEDED(NS_NewURI(getter_AddRefs(filenameURI), frame.mFilename)) &&
-      NS_SUCCEEDED(filenameURI->GetPassword(pass)) && !pass.IsEmpty()) {
-    nsCOMPtr<nsISensitiveInfoHiddenURI> safeURI = do_QueryInterface(filenameURI);
-    nsAutoCString spec;
-    if (safeURI &&
-        NS_SUCCEEDED(safeURI->GetSensitiveInfoHiddenSpec(spec))) {
-      CopyUTF8toUTF16(spec, event.mFilename);
-    }
-  }
-
-  event.mLineNumber = frame.mLineNumber;
-  event.mColumnNumber = frame.mColumnNumber;
-  event.mFunctionName = frame.mFunctionName;
-  event.mTimeStamp = aData->mTimeStamp;
-  event.mPrivate = aData->mPrivate;
-
-  switch (aData->mMethodName) {
-    case MethodLog:
-    case MethodInfo:
-    case MethodWarn:
-    case MethodError:
-    case MethodException:
-    case MethodDebug:
-    case MethodAssert:
-      event.mArguments.Construct();
-      event.mStyles.Construct();
-      if (NS_WARN_IF(!ProcessArguments(aCx, aArguments,
-                                       event.mArguments.Value(),
-                                       event.mStyles.Value()))) {
-        return false;
-      }
-
-      break;
-
-    default:
-      event.mArguments.Construct();
-      if (NS_WARN_IF(!ArgumentsToValueList(aArguments,
-                                           event.mArguments.Value()))) {
-        return false;
-      }
-  }
-
-  if (aData->mMethodName == MethodGroup ||
-      aData->mMethodName == MethodGroupCollapsed ||
-      aData->mMethodName == MethodGroupEnd) {
-    ComposeGroupName(aCx, aArguments, event.mGroupName);
-  }
-
-  else if (aData->mMethodName == MethodTime && !aArguments.IsEmpty()) {
-    event.mTimer = CreateStartTimerValue(aCx, aData->mStartTimerLabel,
-                                         aData->mStartTimerValue,
-                                         aData->mStartTimerStatus);
-  }
-
-  else if (aData->mMethodName == MethodTimeEnd && !aArguments.IsEmpty()) {
-    event.mTimer = CreateStopTimerValue(aCx, aData->mStopTimerLabel,
-                                        aData->mStopTimerDuration,
-                                        aData->mStopTimerStatus);
-  }
-
-  else if (aData->mMethodName == MethodCount) {
-    event.mCounter = CreateCounterValue(aCx, aData->mCountLabel,
-                                        aData->mCountValue);
-  }
-
-  if (NS_WARN_IF(!ToJSValue(aCx, event, aEventValue))) {
-    return false;
-  }
-
-  JS::Rooted<JSObject*> eventObj(aCx, &aEventValue.toObject());
-  if (NS_WARN_IF(!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventObj,
-                                    JSPROP_ENUMERATE))) {
-    return false;
-  }
-
-  if (ShouldIncludeStackTrace(aData->mMethodName)) {
-    // Now define the "stacktrace" property on eventObj.  There are two cases
-    // here.  Either we came from a worker and have a reified stack, or we want
-    // to define a getter that will lazily reify the stack.
-    if (aData->mReifiedStack) {
-      JS::Rooted<JS::Value> stacktrace(aCx);
-      if (NS_WARN_IF(!ToJSValue(aCx, *aData->mReifiedStack, &stacktrace)) ||
-          NS_WARN_IF(!JS_DefineProperty(aCx, eventObj, "stacktrace", stacktrace,
-                                        JSPROP_ENUMERATE))) {
-        return false;
-      }
-    } else {
-      JSFunction* fun = js::NewFunctionWithReserved(aCx, LazyStackGetter, 0, 0,
-                                                    "stacktrace");
-      if (NS_WARN_IF(!fun)) {
-        return false;
-      }
-
-      JS::Rooted<JSObject*> funObj(aCx, JS_GetFunctionObject(fun));
-
-      // We want to store our stack in the function and have it stay alive.  But
-      // we also need sane access to the C++ nsIStackFrame.  So store both a JS
-      // wrapper and the raw pointer: the former will keep the latter alive.
-      JS::Rooted<JS::Value> stackVal(aCx);
-      nsresult rv = nsContentUtils::WrapNative(aCx, aData->mStack,
-                                               &stackVal);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return false;
-      }
-
-      js::SetFunctionNativeReserved(funObj, SLOT_STACKOBJ, stackVal);
-      js::SetFunctionNativeReserved(funObj, SLOT_RAW_STACK,
-                                    JS::PrivateValue(aData->mStack.get()));
-
-      if (NS_WARN_IF(!JS_DefineProperty(aCx, eventObj, "stacktrace",
-                                        JS::UndefinedHandleValue,
-                                        JSPROP_ENUMERATE | JSPROP_SHARED |
-                                        JSPROP_GETTER | JSPROP_SETTER,
-                                        JS_DATA_TO_FUNC_PTR(JSNative, funObj.get()),
-                                        nullptr))) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 namespace {
 
 // Helper method for ProcessArguments. Flushes output, if non-empty, to aSequence.
 bool
 FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &aOutput)
 {
+  AssertIsOnMainThread();
+
   if (!aOutput.IsEmpty()) {
     JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
                                                        aOutput.get(),
                                                        aOutput.Length()));
-    if (NS_WARN_IF(!str)) {
+    if (!str) {
       return false;
     }
 
-    if (NS_WARN_IF(!aSequence.AppendElement(JS::StringValue(str), fallible))) {
+    if (!aSequence.AppendElement(JS::StringValue(str), fallible)) {
       return false;
     }
 
     aOutput.Truncate();
   }
 
   return true;
 }
@@ -1703,32 +1544,34 @@ FlushOutput(JSContext* aCx, Sequence<JS:
 } // namespace
 
 bool
 Console::ProcessArguments(JSContext* aCx,
                           const Sequence<JS::Value>& aData,
                           Sequence<JS::Value>& aSequence,
                           Sequence<nsString>& aStyles) const
 {
+  AssertIsOnMainThread();
+
   if (aData.IsEmpty()) {
     return true;
   }
 
   if (aData.Length() == 1 || !aData[0].isString()) {
     return ArgumentsToValueList(aData, aSequence);
   }
 
   JS::Rooted<JS::Value> format(aCx, aData[0]);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, format));
-  if (NS_WARN_IF(!jsString)) {
+  if (!jsString) {
     return false;
   }
 
   nsAutoJSString string;
-  if (NS_WARN_IF(!string.init(aCx, jsString))) {
+  if (!string.init(aCx, jsString)) {
     return false;
   }
 
   nsString::const_iterator start, end;
   string.BeginReading(start);
   string.EndReading(end);
 
   nsString output;
@@ -1807,112 +1650,111 @@ Console::ProcessArguments(JSContext* aCx
     char ch = *start;
     tmp.Append(ch);
     ++start;
 
     switch (ch) {
       case 'o':
       case 'O':
       {
-        if (NS_WARN_IF(!FlushOutput(aCx, aSequence, output))) {
+        if (!FlushOutput(aCx, aSequence, output)) {
           return false;
         }
 
         JS::Rooted<JS::Value> v(aCx);
         if (index < aData.Length()) {
           v = aData[index++];
         }
 
-        if (NS_WARN_IF(!aSequence.AppendElement(v, fallible))) {
+        if (!aSequence.AppendElement(v, fallible)) {
           return false;
         }
 
         break;
       }
 
       case 'c':
       {
         // If there isn't any output but there's already a style, then
         // discard the previous style and use the next one instead.
         if (output.IsEmpty() && !aStyles.IsEmpty()) {
           aStyles.TruncateLength(aStyles.Length() - 1);
         }
 
-        if (NS_WARN_IF(!FlushOutput(aCx, aSequence, output))) {
+        if (!FlushOutput(aCx, aSequence, output)) {
           return false;
         }
 
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> v(aCx, aData[index++]);
           JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, v));
-          if (NS_WARN_IF(!jsString)) {
+          if (!jsString) {
             return false;
           }
 
           int32_t diff = aSequence.Length() - aStyles.Length();
           if (diff > 0) {
             for (int32_t i = 0; i < diff; i++) {
-              if (NS_WARN_IF(!aStyles.AppendElement(NullString(),
-                                                    fallible))) {
+              if (!aStyles.AppendElement(NullString(), fallible)) {
                 return false;
               }
             }
           }
 
           nsAutoJSString string;
           if (!string.init(aCx, jsString)) {
             return false;
           }
 
-          if (NS_WARN_IF(!aStyles.AppendElement(string, fallible))) {
+          if (!aStyles.AppendElement(string, fallible)) {
             return false;
           }
         }
         break;
       }
 
       case 's':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
           JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
-          if (NS_WARN_IF(!jsString)) {
+          if (!jsString) {
             return false;
           }
 
           nsAutoJSString v;
-          if (NS_WARN_IF(!v.init(aCx, jsString))) {
+          if (!v.init(aCx, jsString)) {
             return false;
           }
 
           output.Append(v);
         }
         break;
 
       case 'd':
       case 'i':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
 
           int32_t v;
-          if (NS_WARN_IF(!JS::ToInt32(aCx, value, &v))) {
+          if (!JS::ToInt32(aCx, value, &v)) {
             return false;
           }
 
           nsCString format;
           MakeFormatString(format, integer, mantissa, 'd');
           output.AppendPrintf(format.get(), v);
         }
         break;
 
       case 'f':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
 
           double v;
-          if (NS_WARN_IF(!JS::ToNumber(aCx, value, &v))) {
+          if (!JS::ToNumber(aCx, value, &v)) {
             return false;
           }
 
           // nspr returns "nan", but we want to expose it as "NaN"
           if (std::isnan(v)) {
             output.AppendFloat(v);
           } else {
             nsCString format;
@@ -1923,39 +1765,41 @@ Console::ProcessArguments(JSContext* aCx
         break;
 
       default:
         output.Append(tmp);
         break;
     }
   }
 
-  if (NS_WARN_IF(!FlushOutput(aCx, aSequence, output))) {
+  if (!FlushOutput(aCx, aSequence, output)) {
     return false;
   }
 
   // Discard trailing style element if there is no output to apply it to.
   if (aStyles.Length() > aSequence.Length()) {
     aStyles.TruncateLength(aSequence.Length());
   }
 
   // The rest of the array, if unused by the format string.
   for (; index < aData.Length(); ++index) {
-    if (NS_WARN_IF(!aSequence.AppendElement(aData[index], fallible))) {
+    if (!aSequence.AppendElement(aData[index], fallible)) {
       return false;
     }
   }
 
   return true;
 }
 
 void
 Console::MakeFormatString(nsCString& aFormat, int32_t aInteger,
                           int32_t aMantissa, char aCh) const
 {
+  AssertIsOnMainThread();
+
   aFormat.Append('%');
   if (aInteger >= 0) {
     aFormat.AppendInt(aInteger);
   }
 
   if (aMantissa >= 0) {
     aFormat.Append('.');
     aFormat.AppendInt(aMantissa);
@@ -1964,16 +1808,18 @@ Console::MakeFormatString(nsCString& aFo
   aFormat.Append(aCh);
 }
 
 void
 Console::ComposeGroupName(JSContext* aCx,
                           const Sequence<JS::Value>& aData,
                           nsAString& aName) const
 {
+  AssertIsOnMainThread();
+
   for (uint32_t i = 0; i < aData.Length(); ++i) {
     if (i != 0) {
       aName.AppendASCII(" ");
     }
 
     JS::Rooted<JS::Value> value(aCx, aData[i]);
     JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
     if (!jsString) {
@@ -1995,28 +1841,28 @@ Console::StartTimer(JSContext* aCx, cons
                     nsAString& aTimerLabel,
                     DOMHighResTimeStamp* aTimerValue)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aTimerValue);
 
   *aTimerValue = 0;
 
-  if (NS_WARN_IF(mTimerRegistry.Count() >= MAX_PAGE_TIMERS)) {
+  if (mTimerRegistry.Count() >= MAX_PAGE_TIMERS) {
     return false;
   }
 
   JS::Rooted<JS::Value> name(aCx, aName);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, name));
-  if (NS_WARN_IF(!jsString)) {
+  if (!jsString) {
     return false;
   }
 
   nsAutoJSString label;
-  if (NS_WARN_IF(!label.init(aCx, jsString))) {
+  if (!label.init(aCx, jsString)) {
     return false;
   }
 
   DOMHighResTimeStamp entry;
   if (!mTimerRegistry.Get(label, &entry)) {
     mTimerRegistry.Put(label, aTimestamp);
   } else {
     aTimestamp = entry;
@@ -2027,16 +1873,18 @@ Console::StartTimer(JSContext* aCx, cons
   return true;
 }
 
 JS::Value
 Console::CreateStartTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
                                DOMHighResTimeStamp aTimerValue,
                                bool aTimerStatus) const
 {
+  AssertIsOnMainThread();
+
   if (!aTimerStatus) {
     RootedDictionary<ConsoleTimerError> error(aCx);
 
     JS::Rooted<JS::Value> value(aCx);
     if (!ToJSValue(aCx, error, &value)) {
       return JS::UndefinedValue();
     }
 
@@ -2064,41 +1912,43 @@ Console::StopTimer(JSContext* aCx, const
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aTimerDuration);
 
   *aTimerDuration = 0;
 
   JS::Rooted<JS::Value> name(aCx, aName);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, name));
-  if (NS_WARN_IF(!jsString)) {
+  if (!jsString) {
     return false;
   }
 
   nsAutoJSString key;
-  if (NS_WARN_IF(!key.init(aCx, jsString))) {
+  if (!key.init(aCx, jsString)) {
     return false;
   }
 
   DOMHighResTimeStamp entry;
-  if (NS_WARN_IF(!mTimerRegistry.Get(key, &entry))) {
+  if (!mTimerRegistry.Get(key, &entry)) {
     return false;
   }
 
   mTimerRegistry.Remove(key);
 
   aTimerLabel = key;
   *aTimerDuration = aTimestamp - entry;
   return true;
 }
 
 JS::Value
 Console::CreateStopTimerValue(JSContext* aCx, const nsAString& aLabel,
                               double aDuration, bool aStatus) const
 {
+  AssertIsOnMainThread();
+
   if (!aStatus) {
     return JS::UndefinedValue();
   }
 
   RootedDictionary<ConsoleTimerEnd> timer(aCx);
   timer.mName = aLabel;
   timer.mDuration = aDuration;
 
@@ -2109,18 +1959,20 @@ Console::CreateStopTimerValue(JSContext*
 
   return value;
 }
 
 bool
 Console::ArgumentsToValueList(const Sequence<JS::Value>& aData,
                               Sequence<JS::Value>& aSequence) const
 {
+  AssertIsOnMainThread();
+
   for (uint32_t i = 0; i < aData.Length(); ++i) {
-    if (NS_WARN_IF(!aSequence.AppendElement(aData[i], fallible))) {
+    if (!aSequence.AppendElement(aData[i], fallible)) {
       return false;
     }
   }
 
   return true;
 }
 
 uint32_t
@@ -2164,16 +2016,18 @@ Console::IncreaseCounter(JSContext* aCx,
   aCountLabel = label;
   return count;
 }
 
 JS::Value
 Console::CreateCounterValue(JSContext* aCx, const nsAString& aCountLabel,
                             uint32_t aCountValue) const
 {
+  AssertIsOnMainThread();
+
   ClearException ce(aCx);
 
   if (aCountValue == MAX_PAGE_COUNTERS) {
     RootedDictionary<ConsoleCounterError> error(aCx);
 
     JS::Rooted<JS::Value> value(aCx);
     if (!ToJSValue(aCx, error, &value)) {
       return JS::UndefinedValue();
@@ -2225,129 +2079,31 @@ Console::GetOrCreateSandbox(JSContext* a
 
     mSandbox = new JSObjectHolder(aCx, sandbox);
   }
 
   return mSandbox->GetJSObject();
 }
 
 void
-Console::StoreCallData(ConsoleCallData* aCallData)
+Console::RegisterConsoleCallData(ConsoleCallData* aData)
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT(aCallData);
-  MOZ_ASSERT(!mCallDataStorage.Contains(aCallData));
-  MOZ_ASSERT(!mCallDataStoragePending.Contains(aCallData));
 
-  mCallDataStorage.AppendElement(aCallData);
-
-  if (mCallDataStorage.Length() > STORAGE_MAX_EVENTS) {
-    RefPtr<ConsoleCallData> callData = mCallDataStorage[0];
-    mCallDataStorage.RemoveElementAt(0);
-
-    MOZ_ASSERT(callData->mStatus != ConsoleCallData::eToBeDeleted);
-
-    // We cannot delete this object now because we have to trace its JSValues
-    // until the pending operation (ConsoleCallDataRunnable) is completed.
-    if (callData->mStatus == ConsoleCallData::eInUse) {
-      callData->mStatus = ConsoleCallData::eToBeDeleted;
-      mCallDataStoragePending.AppendElement(callData);
-    }
-  }
-}
-
-void
-Console::UnstoreCallData(ConsoleCallData* aCallData)
-{
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(aCallData);
-  MOZ_ASSERT(mCallDataStorage.Contains(aCallData));
-  MOZ_ASSERT(!mCallDataStoragePending.Contains(aCallData));
-
-  mCallDataStorage.RemoveElement(aCallData);
-}
-
-void
-Console::ReleaseCallData(ConsoleCallData* aCallData)
-{
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(aCallData);
-  MOZ_ASSERT(aCallData->mStatus == ConsoleCallData::eToBeDeleted);
-  MOZ_ASSERT(mCallDataStoragePending.Contains(aCallData));
-
-  mCallDataStoragePending.RemoveElement(aCallData);
+  MOZ_ASSERT(!mConsoleCallDataArray.Contains(aData));
+  mConsoleCallDataArray.AppendElement(aData);
 }
 
 void
-Console::NotifyHandler(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
-                       const Sequence<JS::Value>& aArguments,
-                       ConsoleCallData* aCallData) const
-{
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(aCallData);
-
-  if (!mConsoleEventHandler) {
-    return;
-  }
-
-  JSAutoCompartment ac(aCx, mConsoleEventHandler->Callable());
-
-  JS::Rooted<JS::Value> value(aCx);
-  if (NS_WARN_IF(!PopulateEvent(aCx, mConsoleEventHandler->Callable(),
-                                aArguments, &value, aCallData))) {
-    return;
-  }
-
-  ErrorResult rv;
-  JS::Rooted<JS::Value> ignored(aCx);
-  mConsoleEventHandler->Call(value, &ignored, rv);
-  rv.SuppressException();
-}
-
-void
-Console::RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
-                               ErrorResult& aRv)
+Console::UnregisterConsoleCallData(ConsoleCallData* aData)
 {
   AssertIsOnOwningThread();
 
-  // We don't want to expose this functionality to main-thread yet.
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
-
-  for (uint32_t i = 0; i < mCallDataStorage.Length(); ++i) {
-    JS::Rooted<JS::Value> value(aCx);
-
-    Sequence<JS::Value> sequence;
-    if (!mCallDataStorage[i]->PopulateSequenceArguments(sequence)) {
-      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-      return;
-    }
-
-    SequenceRooter<JS::Value> arguments(aCx, &sequence);
-    if (NS_WARN_IF(!PopulateEvent(aCx, global, sequence, &value,
-                                  mCallDataStorage[i]))) {
-      aRv.Throw(NS_ERROR_FAILURE);
-      return;
-    }
-
-    aEvents.AppendElement(value);
-  }
-}
-
-void
-Console::SetConsoleEventHandler(AnyCallback& aHandler)
-{
-  AssertIsOnOwningThread();
-
-  // We don't want to expose this functionality to main-thread yet.
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  mConsoleEventHandler = &aHandler;
+  MOZ_ASSERT(mConsoleCallDataArray.Contains(aData));
+  mConsoleCallDataArray.RemoveElement(aData);
 }
 
 void
 Console::AssertIsOnOwningThread() const
 {
   MOZ_ASSERT(mOwningThread);
   MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
 }
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -20,17 +20,16 @@
 #include "nsPIDOMWindow.h"
 
 class nsIConsoleAPIStorage;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
-class AnyCallback;
 class ConsoleCallData;
 class ConsoleRunnable;
 class ConsoleCallDataRunnable;
 class ConsoleProfileRunnable;
 struct ConsoleStackEntry;
 
 class Console final : public nsIObserver
                     , public nsWrapperCache
@@ -38,18 +37,17 @@ class Console final : public nsIObserver
 {
   ~Console();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
   NS_DECL_NSIOBSERVER
 
-  static already_AddRefed<Console>
-  Create(nsPIDOMWindowInner* aWindow, ErrorResult& aRv);
+  explicit Console(nsPIDOMWindowInner* aWindow);
 
   // WebIDL methods
   nsPIDOMWindowInner* GetParentObject() const
   {
     return mWindow;
   }
 
   virtual JSObject*
@@ -113,35 +111,17 @@ public:
   Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData);
 
   void
   Count(JSContext* aCx, const Sequence<JS::Value>& aData);
 
   void
   NoopMethod();
 
-  void
-  RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
-                        ErrorResult& aRv);
-
-  void
-  SetConsoleEventHandler(AnyCallback& aHandler);
-
-  void
-  ClearStorage();
-
-  void
-  Shutdown();
-
 private:
-  explicit Console(nsPIDOMWindowInner* aWindow);
-
-  void
-  Initialize(ErrorResult& aRv);
-
   enum MethodName
   {
     MethodLog,
     MethodInfo,
     MethodWarn,
     MethodError,
     MethodException,
     MethodDebug,
@@ -163,39 +143,16 @@ private:
   Method(JSContext* aCx, MethodName aName, const nsAString& aString,
          const Sequence<JS::Value>& aData);
 
   void
   ProcessCallData(ConsoleCallData* aData,
                   JS::Handle<JSObject*> aGlobal,
                   const Sequence<JS::Value>& aArguments);
 
-  void
-  StoreCallData(ConsoleCallData* aData);
-
-  void
-  UnstoreCallData(ConsoleCallData* aData);
-
-  // Read in Console.cpp how this method is used.
-  void
-  ReleaseCallData(ConsoleCallData* aCallData);
-
-  void
-  NotifyHandler(JSContext* aCx,
-                JS::Handle<JSObject*> aGlobal,
-                const Sequence<JS::Value>& aArguments,
-                ConsoleCallData* aData) const;
-
-  bool
-  PopulateEvent(JSContext* aCx,
-                JS::Handle<JSObject*> aGlobal,
-                const Sequence<JS::Value>& aArguments,
-                JS::MutableHandle<JS::Value> aValue,
-                ConsoleCallData* aData) const;
-
   // If the first JS::Value of the array is a string, this method uses it to
   // format a string. The supported sequences are:
   //   %s    - string
   //   %d,%i - integer
   //   %f    - double
   //   %o,%O - a JS object.
   //   %c    - style string.
   // The output is an array where any object is a separated item, the rest is
@@ -237,50 +194,51 @@ private:
   // * aTimerValue - the StartTimer value stored into (or taken from)
   //                 mTimerRegistry.
   bool
   StartTimer(JSContext* aCx, const JS::Value& aName,
              DOMHighResTimeStamp aTimestamp,
              nsAString& aTimerLabel,
              DOMHighResTimeStamp* aTimerValue);
 
-  // CreateStartTimerValue generates a ConsoleTimerStart dictionary exposed as
-  // JS::Value. If aTimerStatus is false, it generates a ConsoleTimerError
-  // instead. It's called only after the execution StartTimer on the owning
-  // thread.
+  // CreateStartTimerValue is called on the main thread only and generates a
+  // ConsoleTimerStart dictionary exposed as JS::Value. If aTimerStatus is
+  // false, it generates a ConsoleTimerError instead. It's called only after
+  // the execution StartTimer on the owning thread.
   // * aCx - this is the context that will root the returned value.
   // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
   // * aTimerValue - this is what StartTimer received as aTimerValue
   // * aTimerStatus - the return value of StartTimer.
   JS::Value
   CreateStartTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
                         DOMHighResTimeStamp aTimerValue,
                         bool aTimerStatus) const;
 
   // StopTimer follows the same pattern as StartTimer: it runs on the
   // owning thread and populates aTimerLabel and aTimerDuration, used by
-  // CreateStopTimerValue. It returns false if a JS exception is thrown or if
-  // the aName timer doesn't exist in the mTimerRegistry.
+  // CreateStopTimerValue on the main thread. It returns false if a JS
+  // exception is thrown or if the aName timer doesn't exist in mTimerRegistry.
   // * aCx - the JSContext rooting aName.
   // * aName - this is (should be) the name of the timer as JS::Value.
   // * aTimestamp - the monotonicTimer for this context (taken from
   //                window->performance.now() or from Now() -
   //                workerPrivate->NowBaseTimeStamp() in workers.
   // * aTimerLabel - This label will be populated with the aName converted to a
   //                 string.
   // * aTimerDuration - the difference between aTimestamp and when the timer
   //                    started (see StartTimer).
   bool
   StopTimer(JSContext* aCx, const JS::Value& aName,
             DOMHighResTimeStamp aTimestamp,
             nsAString& aTimerLabel,
             double* aTimerDuration);
 
-  // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
-  // a ConsoleTimerError dictionary if aTimerStatus is false. See StopTimer.
+  // Executed on the main thread and generates a ConsoleTimerEnd dictionary
+  // exposed as JS::Value, or a ConsoleTimerError dictionary if aTimerStatus is
+  // false. See StopTimer.
   // * aCx - this is the context that will root the returned value.
   // * aTimerLabel - this label must be what StopTimer received as aTimerLabel.
   // * aTimerDuration - this is what StopTimer received as aTimerDuration
   // * aTimerStatus - the return value of StopTimer.
   JS::Value
   CreateStopTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
                        double aTimerDuration,
                        bool aTimerStatus) const;
@@ -290,85 +248,74 @@ private:
   ArgumentsToValueList(const Sequence<JS::Value>& aData,
                        Sequence<JS::Value>& aSequence) const;
 
   void
   ProfileMethod(JSContext* aCx, const nsAString& aAction,
                 const Sequence<JS::Value>& aData);
 
   // This method follows the same pattern as StartTimer: its runs on the owning
-  // thread and populate aCountLabel, used by CreateCounterValue. Returns
-  // MAX_PAGE_COUNTERS in case of error, otherwise the incremented counter
-  // value.
+  // thread and populates aCountLabel, used by CreateCounterValue on the
+  // main thread. Returns MAX_PAGE_COUNTERS in case of error otherwise the
+  // incremented counter value.
   // * aCx - the JSContext rooting aData.
   // * aFrame - the first frame of ConsoleCallData.
   // * aData - the arguments received by the console.count() method.
   // * aCountLabel - the label that will be populated by this method.
   uint32_t
   IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame,
                   const Sequence<JS::Value>& aData,
                   nsAString& aCountLabel);
 
-  // This method generates a ConsoleCounter dictionary as JS::Value. If
-  // aCountValue is == MAX_PAGE_COUNTERS it generates a ConsoleCounterError
-  // instead. See IncreaseCounter.
+  // Executed on the main thread and generates a ConsoleCounter dictionary as
+  // JS::Value. If aCountValue is == MAX_PAGE_COUNTERS it generates a
+  // ConsoleCounterError instead. See IncreaseCounter.
   // * aCx - this is the context that will root the returned value.
   // * aCountLabel - this label must be what IncreaseCounter received as
   //                 aTimerLabel.
   // * aCountValue - the return value of IncreaseCounter.
   JS::Value
   CreateCounterValue(JSContext* aCx, const nsAString& aCountLabel,
                      uint32_t aCountValue) const;
 
   bool
   ShouldIncludeStackTrace(MethodName aMethodName) const;
 
   JSObject*
   GetOrCreateSandbox(JSContext* aCx, nsIPrincipal* aPrincipal);
 
   void
+  RegisterConsoleCallData(ConsoleCallData* aData);
+
+  void
+  UnregisterConsoleCallData(ConsoleCallData* aData);
+
+  void
   AssertIsOnOwningThread() const;
 
   // All these nsCOMPtr are touched on main thread only.
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIConsoleAPIStorage> mStorage;
   RefPtr<JSObjectHolder> mSandbox;
 
   // Touched on the owner thread.
   nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
   nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
 
-  nsTArray<RefPtr<ConsoleCallData>> mCallDataStorage;
-
-  // This array is used in a particular corner-case where:
-  // 1. we are in a worker thread
-  // 2. we have more than STORAGE_MAX_EVENTS
-  // 3. but the main-thread ConsoleCallDataRunnable of the first one is still
-  // running (this means that something very bad is happening on the
-  // main-thread).
-  // When this happens we want to keep the ConsoleCallData alive for traceing
-  // its JSValues also if 'officially' this ConsoleCallData must be removed from
-  // the storage.
-  nsTArray<RefPtr<ConsoleCallData>> mCallDataStoragePending;
-
-  RefPtr<AnyCallback> mConsoleEventHandler;
+  // Raw pointers because ConsoleCallData manages its own
+  // registration/unregistration.
+  nsTArray<ConsoleCallData*> mConsoleCallDataArray;
 
 #ifdef DEBUG
   PRThread* mOwningThread;
 #endif
 
   uint64_t mOuterID;
   uint64_t mInnerID;
 
-  enum {
-    eUnknown,
-    eInitialized,
-    eShuttingDown
-  } mStatus;
-
   friend class ConsoleCallData;
   friend class ConsoleRunnable;
   friend class ConsoleCallDataRunnable;
   friend class ConsoleProfileRunnable;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13756,20 +13756,17 @@ nsGlobalWindow::Orientation() const
 #endif
 
 Console*
 nsGlobalWindow::GetConsole(ErrorResult& aRv)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mConsole) {
-    mConsole = Console::Create(AsInner(), aRv);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return nullptr;
-    }
+    mConsole = new Console(AsInner());
   }
 
   return mConsole;
 }
 
 already_AddRefed<External>
 nsGlobalWindow::GetExternal(ErrorResult& aRv)
 {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1597,30 +1597,31 @@ DOMInterfaces = {
         'terminate',
     ],
 },
 
 'WorkerDebuggerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'nativeType': 'mozilla::dom::workers::WorkerDebuggerGlobalScope',
     'implicitJSContext': [
-        'dump', 'global', 'reportError', 'setConsoleEventHandler',
+        'dump', 'global', 'reportError',
     ],
 },
 
 'WorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
     'concrete': False,
     'implicitJSContext': [
         'close',
     ],
     # Rename a few things so we don't have both classes and methods
     # with the same name
     'binaryNames': {
+        'console': 'getConsole',
         'performance': 'getPerformance',
     },
 },
 
 'WorkerLocation': {
     'headerFile': 'mozilla/dom/workers/bindings/Location.h',
     'workers': True,
 },
--- a/dom/webidl/WorkerDebuggerGlobalScope.webidl
+++ b/dom/webidl/WorkerDebuggerGlobalScope.webidl
@@ -19,22 +19,16 @@ interface WorkerDebuggerGlobalScope : Ev
   void postMessage(DOMString message);
 
   attribute EventHandler onmessage;
 
   [Throws]
   void setImmediate(Function handler);
 
   void reportError(DOMString message);
-
-  [Throws]
-  sequence<any> retrieveConsoleEvents();
-
-  [Throws]
-  void setConsoleEventHandler(AnyCallback handler);
 };
 
 // So you can debug while you debug
 partial interface WorkerDebuggerGlobalScope {
   void dump(optional DOMString string);
 
   [Throws, Replaceable]
   readonly attribute Console console;
--- a/dom/webidl/WorkerGlobalScope.webidl
+++ b/dom/webidl/WorkerGlobalScope.webidl
@@ -12,17 +12,17 @@
  * this document.
  */
 
 [Exposed=(Worker)]
 interface WorkerGlobalScope : EventTarget {
   [Constant, Cached]
   readonly attribute WorkerGlobalScope self;
 
-  [Throws, Replaceable]
+  [Replaceable]
   readonly attribute Console console;
 
   readonly attribute WorkerLocation location;
 
   [Throws]
   void close();
   attribute OnErrorEventHandler onerror;
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2445,22 +2445,16 @@ RuntimeService::CycleCollectAllWorkers()
 }
 
 void
 RuntimeService::SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline)
 {
   BROADCAST_ALL_WORKERS(OfflineStatusChangeEvent, aIsOffline);
 }
 
-void
-RuntimeService::MemoryPressureAllWorkers()
-{
-  BROADCAST_ALL_WORKERS(MemoryPressure, /* dummy = */ false);
-}
-
 // nsISupports
 NS_IMPL_ISUPPORTS(RuntimeService, nsIObserver)
 
 // nsIObserver
 NS_IMETHODIMP
 RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
                         const char16_t* aData)
 {
@@ -2479,17 +2473,16 @@ RuntimeService::Observe(nsISupports* aSu
     return NS_OK;
   }
   if (!strcmp(aTopic, CC_REQUEST_OBSERVER_TOPIC)) {
     CycleCollectAllWorkers();
     return NS_OK;
   }
   if (!strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
     GarbageCollectAllWorkers(/* shrinking = */ true);
-    MemoryPressureAllWorkers();
     CycleCollectAllWorkers();
     return NS_OK;
   }
   if (!strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
     SendOfflineStatusChangeEventToAllWorkers(NS_IsOffline());
     return NS_OK;
   }
   if (!strcmp(aTopic, NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC)) {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -244,19 +244,16 @@ public:
   GarbageCollectAllWorkers(bool aShrinking);
 
   void
   CycleCollectAllWorkers();
 
   void
   SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline);
 
-  void
-  MemoryPressureAllWorkers();
-
 private:
   RuntimeService();
   ~RuntimeService();
 
   nsresult
   Init();
 
   void
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -39,17 +39,16 @@
 #include "js/MemoryMetrics.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Likely.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/Console.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
@@ -1534,31 +1533,16 @@ public:
     aWorkerPrivate->OfflineStatusChangeEventInternal(mIsOffline);
     return true;
   }
 
 private:
   bool mIsOffline;
 };
 
-class MemoryPressureRunnable : public WorkerControlRunnable
-{
-public:
-  explicit MemoryPressureRunnable(WorkerPrivate* aWorkerPrivate)
-    : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
-  {}
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    aWorkerPrivate->MemoryPressureInternal();
-    return true;
-  }
-};
-
 #ifdef DEBUG
 static bool
 StartsWithExplicit(nsACString& s)
 {
     return StringBeginsWith(s, NS_LITERAL_CSTRING("explicit/"));
 }
 #endif
 
@@ -3118,27 +3102,16 @@ WorkerPrivate::OfflineStatusChangeEventI
 
   event->InitEvent(eventType, false, false);
   event->SetTrusted(true);
 
   globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 template <class Derived>
-void
-WorkerPrivateParent<Derived>::MemoryPressure(bool aDummy)
-{
-  AssertIsOnParentThread();
-
-  RefPtr<MemoryPressureRunnable> runnable =
-    new MemoryPressureRunnable(ParentAsWorkerPrivate());
-  NS_WARN_IF(!runnable->Dispatch());
-}
-
-template <class Derived>
 bool
 WorkerPrivateParent<Derived>::RegisterSharedWorker(SharedWorker* aSharedWorker,
                                                    MessagePort* aPort)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aSharedWorker);
   MOZ_ASSERT(IsSharedWorker());
   MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
@@ -6294,31 +6267,16 @@ WorkerPrivate::CycleCollectInternal(bool
   if (aCollectChildren) {
     for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
       mChildWorkers[index]->CycleCollect(/* dummy = */ false);
     }
   }
 }
 
 void
-WorkerPrivate::MemoryPressureInternal()
-{
-  AssertIsOnWorkerThread();
-
-  RefPtr<Console> console = mScope ? mScope->GetConsoleIfExists() : nullptr;
-  if (console) {
-    console->ClearStorage();
-  }
-
-  for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
-    mChildWorkers[index]->MemoryPressure(false);
-  }
-}
-
-void
 WorkerPrivate::SetThread(WorkerThread* aThread)
 {
   if (aThread) {
 #ifdef DEBUG
     {
       bool isOnCurrentThread;
       MOZ_ASSERT(NS_SUCCEEDED(aThread->IsOnCurrentThread(&isOnCurrentThread)));
       MOZ_ASSERT(isOnCurrentThread);
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -368,19 +368,16 @@ public:
   GarbageCollect(bool aShrinking);
 
   void
   CycleCollect(bool aDummy);
 
   void
   OfflineStatusChangeEvent(bool aIsOffline);
 
-  void
-  MemoryPressure(bool aDummy);
-
   bool
   RegisterSharedWorker(SharedWorker* aSharedWorker, MessagePort* aPort);
 
   void
   BroadcastErrorToSharedWorkers(JSContext* aCx,
                                 const nsAString& aMessage,
                                 const nsAString& aFilename,
                                 const nsAString& aLine,
@@ -1192,19 +1189,16 @@ public:
                          bool aCollectChildren);
 
   void
   CycleCollectInternal(bool aCollectChildren);
 
   void
   OfflineStatusChangeEventInternal(bool aIsOffline);
 
-  void
-  MemoryPressureInternal();
-
   JSContext*
   GetJSContext() const
   {
     AssertIsOnWorkerThread();
     return mJSContext;
   }
 
   WorkerGlobalScope*
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -112,25 +112,22 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEvent
 
 JSObject*
 WorkerGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   MOZ_CRASH("We should never get here!");
 }
 
 Console*
-WorkerGlobalScope::GetConsole(ErrorResult& aRv)
+WorkerGlobalScope::GetConsole()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (!mConsole) {
-    mConsole = Console::Create(nullptr, aRv);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return nullptr;
-    }
+    mConsole = new Console(nullptr);
   }
 
   return mConsole;
 }
 
 already_AddRefed<CacheStorage>
 WorkerGlobalScope::GetCaches(ErrorResult& aRv)
 {
@@ -912,55 +909,24 @@ WorkerDebuggerGlobalScope::ReportError(J
 {
   JS::UniqueChars chars;
   uint32_t lineno = 0;
   JS::DescribeScriptedCaller(aCx, &chars, &lineno);
   nsString filename(NS_ConvertUTF8toUTF16(chars.get()));
   mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
 }
 
-void
-WorkerDebuggerGlobalScope::RetrieveConsoleEvents(JSContext* aCx,
-                                                 nsTArray<JS::Value>& aEvents,
-                                                 ErrorResult& aRv)
-{
-  RefPtr<Console> console =
-    mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetConsole(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  console->RetrieveConsoleEvents(aCx, aEvents, aRv);
-}
-
-void
-WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx,
-                                                  AnyCallback& aHandler,
-                                                  ErrorResult& aRv)
-{
-  RefPtr<Console> console =
-    mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetConsole(aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return;
-  }
-
-  console->SetConsoleEventHandler(aHandler);
-}
-
 Console*
 WorkerDebuggerGlobalScope::GetConsole(ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   // Debugger console has its own console object.
   if (!mConsole) {
-    mConsole = Console::Create(nullptr, aRv);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return nullptr;
-    }
+    mConsole = new Console(nullptr);
   }
 
   return mConsole;
 }
 
 void
 WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
                                 const Optional<nsAString>& aString) const
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -12,17 +12,16 @@
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/RequestBinding.h"
 #include "nsWeakReference.h"
 #include "mozilla/dom/ImageBitmapSource.h"
 
 namespace mozilla {
 namespace dom {
 
-class AnyCallback;
 class Console;
 class Function;
 class IDBFactory;
 class Promise;
 class RequestOrUSVString;
 class ServiceWorkerRegistrationWorkerThread;
 
 namespace cache {
@@ -81,23 +80,17 @@ public:
 
   WorkerGlobalScope*
   Self()
   {
     return this;
   }
 
   Console*
-  GetConsole(ErrorResult& aRv);
-
-  Console*
-  GetConsoleIfExists() const
-  {
-    return mConsole;
-  }
+  GetConsole();
 
   already_AddRefed<WorkerLocation>
   Location();
 
   already_AddRefed<WorkerNavigator>
   Navigator();
 
   already_AddRefed<WorkerNavigator>
@@ -328,24 +321,16 @@ public:
   IMPL_EVENT_HANDLER(message)
 
   void
   SetImmediate(Function& aHandler, ErrorResult& aRv);
 
   void
   ReportError(JSContext* aCx, const nsAString& aMessage);
 
-  void
-  RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
-                        ErrorResult& aRv);
-
-  void
-  SetConsoleEventHandler(JSContext* aCx, AnyCallback& aHandler,
-                         ErrorResult& aRv);
-
   Console*
   GetConsole(ErrorResult& aRv);
 
   void
   Dump(JSContext* aCx, const Optional<nsAString>& aString) const;
 
 private:
   virtual ~WorkerDebuggerGlobalScope();
deleted file mode 100644
--- a/dom/workers/test/WorkerDebugger.console_childWorker.js
+++ /dev/null
@@ -1,3 +0,0 @@
-"use strict";
-
-self.onmessage = function () {};
deleted file mode 100644
--- a/dom/workers/test/WorkerDebugger.console_debugger.js
+++ /dev/null
@@ -1,37 +0,0 @@
-"use strict"
-
-function ok(a, msg) {
-  postMessage(JSON.stringify({ type: 'status', what: !!a, msg: msg }));
-}
-
-function is(a, b, msg) {
-  ok(a === b, msg);
-}
-
-function finish() {
-  postMessage(JSON.stringify({ type: 'finish' }));
-}
-
-function magic() {
-  console.log("Hello from the debugger script!");
-
-  var foo = retrieveConsoleEvents();
-  ok(Array.isArray(foo), "We received an array.");
-  ok(foo.length >= 2, "At least 2 messages.");
-
-  is(foo[0].arguments[0], "Can you see this console message?", "First message ok.");
-  is(foo[1].arguments[0], "Can you see this second console message?", "Second message ok.");
-
-  setConsoleEventHandler(function(consoleData) {
-    is(consoleData.arguments[0], "Random message.", "Random message ok!");
-    finish();
-  });
-}
-
-this.onmessage = function (event) {
-  switch (event.data) {
-  case "do magic":
-    magic();
-    break;
-  }
-};
deleted file mode 100644
--- a/dom/workers/test/WorkerDebugger.console_worker.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-console.log("Can you see this console message?");
-console.warn("Can you see this second console message?");
-
-var worker = new Worker("WorkerDebugger.console_childWorker.js");
-
-setInterval(function() {
-  console.log("Random message.");
-}, 200);
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -1,14 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' || os == 'android'
 support-files =
-  WorkerDebugger.console_childWorker.js
-  WorkerDebugger.console_debugger.js
-  WorkerDebugger.console_worker.js
   WorkerDebugger.initialize_childWorker.js
   WorkerDebugger.initialize_debugger.js
   WorkerDebugger.initialize_worker.js
   WorkerDebugger.postMessage_childWorker.js
   WorkerDebugger.postMessage_debugger.js
   WorkerDebugger.postMessage_worker.js
   WorkerDebugger_frozen_iframe1.html
   WorkerDebugger_frozen_iframe2.html
@@ -60,17 +57,16 @@ support-files =
 [test_WorkerDebugger.initialize.xul]
 [test_WorkerDebugger.postMessage.xul]
 [test_WorkerDebugger.xul]
 [test_WorkerDebuggerGlobalScope.createSandbox.xul]
 [test_WorkerDebuggerGlobalScope.enterEventLoop.xul]
 [test_WorkerDebuggerGlobalScope.reportError.xul]
 [test_WorkerDebuggerGlobalScope.setImmediate.xul]
 [test_WorkerDebuggerManager.xul]
-[test_WorkerDebugger_console.xul]
 [test_WorkerDebugger_frozen.xul]
 [test_WorkerDebugger_suspended.xul]
 [test_bug883784.xul]
 [test_chromeWorker.xul]
 [test_chromeWorkerJSM.xul]
 [test_extension.xul]
 [test_extensionBootstrap.xul]
 [test_file.xul]
deleted file mode 100644
--- a/dom/workers/test/test_WorkerDebugger_console.xul
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<window title="Test for WorkerDebuggerGlobalScope.console methods"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        onload="test();">
-
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
-  <script type="application/javascript" src="dom_worker_helper.js"/>
-
-  <script type="application/javascript">
-  <![CDATA[
-
-    const WORKER_URL = "WorkerDebugger.console_worker.js";
-    const CHILD_WORKER_URL = "WorkerDebugger.console_childWorker.js";
-    const DEBUGGER_URL = BASE_URL + "WorkerDebugger.console_debugger.js";
-
-    consoleMessagesReceived = 0;
-    function test() {
-      function consoleListener() {
-        SpecialPowers.addObserver(this, "console-api-log-event", false);
-      }
-
-      consoleListener.prototype  = {
-        observe: function(aSubject, aTopic, aData) {
-          if (aTopic == "console-api-log-event") {
-            var obj = aSubject.wrappedJSObject;
-            if (obj.arguments[0] == "Hello from the debugger script!" &&
-                !consoleMessagesReceived) {
-              consoleMessagesReceived++;
-              ok(true, "Something has been received");
-              SpecialPowers.removeObserver(this, "console-api-log-event");
-            }
-          }
-        }
-      }
-
-      var cl = new consoleListener();
-
-      Task.spawn(function* () {
-        SimpleTest.waitForExplicitFinish();
-
-        info("Create a worker that creates a child worker, wait for their " +
-             "debuggers to be registered, and initialize them.");
-        let promise = waitForMultiple([
-          waitForRegister(WORKER_URL, DEBUGGER_URL),
-          waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
-        ]);
-        let worker = new Worker(WORKER_URL);
-        let [dbg, childDbg] = yield promise;
-
-        info("Send a request to the worker debugger. This should cause the " +
-             "the worker debugger to send a response.");
-        dbg.addListener({
-          onMessage: function(msg) {
-            try {
-              msg = JSON.parse(msg);
-            } catch(e) {
-              ok(false, "Something went wrong");
-              return;
-            }
-
-            if (msg.type == 'finish') {
-              ok(consoleMessagesReceived, "We received something via debugger console!");
-              dbg.removeListener(this);
-              SimpleTest.finish();
-              return;
-            }
-
-            if (msg.type == 'status') {
-              ok(msg.what, msg.msg);
-              return;
-            }
-
-            ok(false, "Something went wrong");
-          }
-        });
-
-        dbg.postMessage("do magic");
-      });
-    }
-
-  ]]>
-  </script>
-
-  <body xmlns="http://www.w3.org/1999/xhtml">
-    <p id="display"></p>
-    <div id="content" style="display:none;"></div>
-    <pre id="test"></pre>
-  </body>
-  <label id="test-result"/>
-</window>