Bug 1328964 - part 3 - Console API exposed to worklets r=smaug draft
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 12 Apr 2018 16:21:20 +1200
changeset 780858 cec368f75bc4b6ffd05e6f1f1b9b79a2b85ed09f
parent 780857 2d356616204dc437ed28d5b46a80c0842ec31ec8
child 780859 9f75cdf217142a2f54930a1d4ac1f70c4d70dbbb
push id106145
push userktomlinson@mozilla.com
push dateThu, 12 Apr 2018 05:09:40 +0000
reviewerssmaug
bugs1328964
milestone61.0a1
Bug 1328964 - part 3 - Console API exposed to worklets r=smaug Initial version r=smaug. Rebased to c616a6fd5e4b by Jan-Ivar Bruaroey <jib@mozilla.com> r=karlt. Rebased to 83de58ddda20 by Karl Tomlinson <karlt+@karlt.net> r=baku. MozReview-Commit-ID: G5E5OXydj3a
dom/console/Console.cpp
dom/console/Console.h
dom/console/ConsoleInstance.cpp
dom/worklet/Worklet.cpp
dom/worklet/Worklet.h
dom/worklet/WorkletGlobalScope.cpp
dom/worklet/WorkletThread.cpp
dom/worklet/WorkletThread.h
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -293,32 +293,393 @@ public:
 private:
   ~ConsoleCallData()
   {
     AssertIsOnOwningThread();
     MOZ_ASSERT(mStatus != eInUse);
   }
 };
 
-class ConsoleRunnable : public WorkerProxyToMainThreadRunnable
-                      , public StructuredCloneHolderBase
+// This base class must be extended for Worker and for Worklet.
+class ConsoleRunnable : public StructuredCloneHolderBase
 {
 public:
-  explicit ConsoleRunnable(Console* aConsole)
-    : WorkerProxyToMainThreadRunnable(GetCurrentThreadWorkerPrivate())
-    , mConsole(aConsole)
-  {}
-
   virtual
   ~ConsoleRunnable()
   {
     // Clear the StructuredCloneHolderBase class.
     Clear();
   }
 
+protected:
+  JSObject*
+  CustomReadHandler(JSContext* aCx,
+                    JSStructuredCloneReader* aReader,
+                    uint32_t aTag,
+                    uint32_t aIndex) override
+  {
+    AssertIsOnMainThread();
+
+    if (aTag == CONSOLE_TAG_BLOB) {
+      MOZ_ASSERT(mClonedData.mBlobs.Length() > aIndex);
+
+      JS::Rooted<JS::Value> val(aCx);
+      {
+        RefPtr<Blob> blob =
+          Blob::Create(mClonedData.mParent,
+                       mClonedData.mBlobs.ElementAt(aIndex));
+        if (!ToJSValue(aCx, blob, &val)) {
+          return nullptr;
+        }
+      }
+
+      return &val.toObject();
+    }
+
+    MOZ_CRASH("No other tags are supported.");
+    return nullptr;
+  }
+
+  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()))) {
+        return false;
+      }
+
+      mClonedData.mBlobs.AppendElement(blob->Impl());
+      return true;
+    }
+
+    if (!JS_ObjectNotWritten(aWriter, aObj)) {
+      return false;
+    }
+
+    JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
+    JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
+    if (NS_WARN_IF(!jsString)) {
+      return false;
+    }
+
+    if (NS_WARN_IF(!JS_WriteString(aWriter, jsString))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  // Helper methods for CallData
+  bool
+  StoreConsoleData(JSContext* aCx, ConsoleCallData* aCallData)
+  {
+    ConsoleCommon::ClearException ce(aCx);
+
+    JS::Rooted<JSObject*> arguments(aCx,
+      JS_NewArrayObject(aCx, aCallData->mCopiedArguments.Length()));
+    if (NS_WARN_IF(!arguments)) {
+      return false;
+    }
+
+    JS::Rooted<JS::Value> arg(aCx);
+    for (uint32_t i = 0; i < aCallData->mCopiedArguments.Length(); ++i) {
+      arg = aCallData->mCopiedArguments[i];
+      if (NS_WARN_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))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  void
+  ProcessCallData(JSContext* aCx, Console* aConsole, ConsoleCallData* aCallData)
+  {
+    AssertIsOnMainThread();
+
+    ConsoleCommon::ClearException ce(aCx);
+
+    JS::Rooted<JS::Value> argumentsValue(aCx);
+    if (!Read(aCx, &argumentsValue)) {
+      return;
+    }
+
+    MOZ_ASSERT(argumentsValue.isObject());
+
+    JS::Rooted<JSObject*> argumentsObj(aCx, &argumentsValue.toObject());
+
+    uint32_t length;
+    if (!JS_GetArrayLength(aCx, argumentsObj, &length)) {
+      return;
+    }
+
+    Sequence<JS::Value> values;
+    SequenceRooter<JS::Value> arguments(aCx, &values);
+
+    for (uint32_t i = 0; i < length; ++i) {
+      JS::Rooted<JS::Value> value(aCx);
+
+      if (!JS_GetElement(aCx, argumentsObj, i, &value)) {
+        return;
+      }
+
+      if (!values.AppendElement(value, fallible)) {
+        return;
+      }
+    }
+
+    MOZ_ASSERT(values.Length() == length);
+
+    aConsole->ProcessCallData(aCx, aCallData, values);
+  }
+
+  void
+  ReleaseCallData(Console* aConsole, ConsoleCallData* aCallData)
+  {
+    aConsole->AssertIsOnOwningThread();
+
+    if (aCallData->mStatus == ConsoleCallData::eToBeDeleted) {
+      aConsole->ReleaseCallData(aCallData);
+    } else {
+      MOZ_ASSERT(aCallData->mStatus == ConsoleCallData::eInUse);
+      aCallData->mStatus = ConsoleCallData::eUnused;
+    }
+  }
+
+  // Helper methods for Profile calls
+  bool
+  StoreProfileData(JSContext* aCx, const Sequence<JS::Value>& aArguments)
+  {
+    ConsoleCommon::ClearException ce(aCx);
+
+    JS::Rooted<JSObject*> arguments(aCx,
+      JS_NewArrayObject(aCx, aArguments.Length()));
+    if (NS_WARN_IF(!arguments)) {
+      return false;
+    }
+
+    JS::Rooted<JS::Value> arg(aCx);
+    for (uint32_t i = 0; i < aArguments.Length(); ++i) {
+      arg = aArguments[i];
+      if (NS_WARN_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))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  void
+  ProcessProfileData(JSContext* aCx, Console* aConsole,
+                     Console::MethodName aMethodName, const nsAString& aAction)
+  {
+    AssertIsOnMainThread();
+
+    ConsoleCommon::ClearException ce(aCx);
+
+    JS::Rooted<JS::Value> argumentsValue(aCx);
+    bool ok = Read(aCx, &argumentsValue);
+    mClonedData.mParent = nullptr;
+
+    if (!ok) {
+      return;
+    }
+
+    MOZ_ASSERT(argumentsValue.isObject());
+    JS::Rooted<JSObject*> argumentsObj(aCx, &argumentsValue.toObject());
+    if (NS_WARN_IF(!argumentsObj)) {
+      return;
+    }
+
+    uint32_t length;
+    if (!JS_GetArrayLength(aCx, argumentsObj, &length)) {
+      return;
+    }
+
+    Sequence<JS::Value> arguments;
+
+    for (uint32_t i = 0; i < length; ++i) {
+      JS::Rooted<JS::Value> value(aCx);
+
+      if (!JS_GetElement(aCx, argumentsObj, i, &value)) {
+        return;
+      }
+
+      if (!arguments.AppendElement(value, fallible)) {
+        return;
+      }
+    }
+
+    aConsole->ProfileMethodInternal(aCx, aMethodName, aAction, arguments);
+  }
+
+  ConsoleStructuredCloneData mClonedData;
+};
+
+class ConsoleWorkletRunnable : public Runnable
+                             , public ConsoleRunnable
+{
+protected:
+  explicit ConsoleWorkletRunnable(Console* aConsole)
+    : Runnable("dom::console::ConsoleWorkletRunnable")
+    , mConsole(aConsole)
+    , mWorkletThread(WorkletThread::Get())
+  {
+    WorkletThread::AssertIsOnWorkletThread();
+    MOZ_ASSERT(mWorkletThread);
+  }
+
+  virtual
+  ~ConsoleWorkletRunnable() = default;
+
+  NS_IMETHOD
+  Run() override
+  {
+    // This runnable is dispatched to main-thread first, then it goes back to
+    // worklet thread.
+    if (NS_IsMainThread()) {
+      RunOnMainThread();
+      RefPtr<ConsoleWorkletRunnable> runnable(this);
+      return mWorkletThread->DispatchRunnable(runnable.forget());
+    }
+
+    WorkletThread::AssertIsOnWorkletThread();
+
+    ReleaseData();
+    mConsole = nullptr;
+    return NS_OK;
+  }
+
+protected:
+  // This method is called in the main-thread.
+  virtual void
+  RunOnMainThread() = 0;
+
+  // This method is called in the owning thread of the Console object.
+  virtual void
+  ReleaseData() = 0;
+
+  // This must be released on the worker thread.
+  RefPtr<Console> mConsole;
+
+  RefPtr<WorkletThread> mWorkletThread;
+};
+
+// This runnable appends a CallData object into the Console queue running on
+// the main-thread.
+class ConsoleCallDataWorkletRunnable final : public ConsoleWorkletRunnable
+{
+public:
+  static already_AddRefed<ConsoleCallDataWorkletRunnable>
+  Create(Console* aConsole, ConsoleCallData* aConsoleData)
+  {
+    WorkletThread::AssertIsOnWorkletThread();
+
+    RefPtr<WorkletThread> workletThread = WorkletThread::Get();
+    MOZ_ASSERT(workletThread);
+
+    aConsoleData->SetIDs(workletThread->GetWorkletLoadInfo().OuterWindowID(),
+                         workletThread->GetWorkletLoadInfo().InnerWindowID());
+
+    RefPtr<ConsoleCallDataWorkletRunnable> runnable =
+      new ConsoleCallDataWorkletRunnable(aConsole, aConsoleData);
+
+    if (!runnable->StoreConsoleData(WorkletThread::Get()->GetJSContext(),
+                                    aConsoleData)) {
+      return nullptr;
+    }
+
+    return runnable.forget();
+  }
+
+private:
+  ConsoleCallDataWorkletRunnable(Console* aConsole,
+                                 ConsoleCallData* aCallData)
+    : ConsoleWorkletRunnable(aConsole)
+    , mCallData(aCallData)
+  {
+    WorkletThread::AssertIsOnWorkletThread();
+    MOZ_ASSERT(aCallData);
+    aCallData->AssertIsOnOwningThread();
+
+    // Marking this CallData as in use.
+    mCallData->mStatus = ConsoleCallData::eInUse;
+  }
+
+  ~ConsoleCallDataWorkletRunnable()
+  {
+    MOZ_ASSERT(!mCallData);
+  }
+
+  virtual void
+  RunOnMainThread() override
+  {
+    AutoSafeJSContext cx;
+
+    JSObject* sandbox =
+      mConsole->GetOrCreateSandbox(cx,
+                                   mWorkletThread->GetWorkletLoadInfo().Principal());
+    JS::Rooted<JSObject*> global(cx, sandbox);
+    if (NS_WARN_IF(!global)) {
+      return;
+    }
+
+    // The CreateSandbox call returns a proxy to the actual sandbox object. We
+    // don't need a proxy here.
+    global = js::UncheckedUnwrap(global);
+
+    JSAutoCompartment ac(cx, global);
+
+    // We don't need to set a parent object in mCallData bacause there are not
+    // DOM objects exposed to worklet.
+
+    ProcessCallData(cx, mConsole, mCallData);
+  }
+
+  virtual void
+  ReleaseData() override
+  {
+    ReleaseCallData(mConsole, mCallData);
+    mCallData = nullptr;
+  }
+
+  RefPtr<ConsoleCallData> mCallData;
+};
+
+class ConsoleWorkerRunnable : public WorkerProxyToMainThreadRunnable
+                            , public ConsoleRunnable
+{
+public:
+  explicit ConsoleWorkerRunnable(Console* aConsole)
+    : WorkerProxyToMainThreadRunnable(GetCurrentThreadWorkerPrivate())
+    , mConsole(aConsole)
+  {}
+
+  virtual
+  ~ConsoleWorkerRunnable() = default;
+
   bool
   Dispatch(JSContext* aCx)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     if (NS_WARN_IF(!PreDispatch(aCx))) {
       RunBackOnWorkerThreadForCleanup();
       return false;
@@ -421,135 +782,50 @@ protected:
   virtual void
   RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
              nsPIDOMWindowInner* aInnerWindow) = 0;
 
   // This method is called in the owning thread of the Console object.
   virtual void
   ReleaseData() = 0;
 
-  virtual JSObject* CustomReadHandler(JSContext* aCx,
-                                      JSStructuredCloneReader* aReader,
-                                      uint32_t aTag,
-                                      uint32_t aIndex) override
-  {
-    AssertIsOnMainThread();
-
-    if (aTag == CONSOLE_TAG_BLOB) {
-      MOZ_ASSERT(mClonedData.mBlobs.Length() > aIndex);
-
-      JS::Rooted<JS::Value> val(aCx);
-      {
-        RefPtr<Blob> blob =
-          Blob::Create(mClonedData.mParent, mClonedData.mBlobs.ElementAt(aIndex));
-        if (!ToJSValue(aCx, blob, &val)) {
-          return nullptr;
-        }
-      }
-
-      return &val.toObject();
-    }
-
-    MOZ_CRASH("No other tags are supported.");
-    return nullptr;
-  }
-
-  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()))) {
-        return false;
-      }
-
-      mClonedData.mBlobs.AppendElement(blob->Impl());
-      return true;
-    }
-
-    if (!JS_ObjectNotWritten(aWriter, aObj)) {
-      return false;
-    }
-
-    JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
-    JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
-    if (NS_WARN_IF(!jsString)) {
-      return false;
-    }
-
-    if (NS_WARN_IF(!JS_WriteString(aWriter, jsString))) {
-      return false;
-    }
-
-    return true;
-  }
-
   // This must be released on the worker thread.
   RefPtr<Console> mConsole;
 
   ConsoleStructuredCloneData mClonedData;
 };
 
 // This runnable appends a CallData object into the Console queue running on
 // the main-thread.
-class ConsoleCallDataRunnable final : public ConsoleRunnable
+class ConsoleCallDataWorkerRunnable final : public ConsoleWorkerRunnable
 {
 public:
-  ConsoleCallDataRunnable(Console* aConsole,
-                          ConsoleCallData* aCallData)
-    : ConsoleRunnable(aConsole)
+  ConsoleCallDataWorkerRunnable(Console* aConsole,
+                                ConsoleCallData* aCallData)
+    : ConsoleWorkerRunnable(aConsole)
     , mCallData(aCallData)
   {
     MOZ_ASSERT(aCallData);
     mWorkerPrivate->AssertIsOnWorkerThread();
     mCallData->AssertIsOnOwningThread();
 
     // Marking this CallData as in use.
     mCallData->mStatus = ConsoleCallData::eInUse;
   }
 
 private:
-  ~ConsoleCallDataRunnable()
+  ~ConsoleCallDataWorkerRunnable()
   {
     MOZ_ASSERT(!mCallData);
   }
 
   bool
   PreDispatch(JSContext* aCx) override
   {
-    mWorkerPrivate->AssertIsOnWorkerThread();
-    mCallData->AssertIsOnOwningThread();
-
-    ConsoleCommon::ClearException ce(aCx);
-
-    JS::Rooted<JSObject*> arguments(aCx,
-      JS_NewArrayObject(aCx, mCallData->mCopiedArguments.Length()));
-    if (NS_WARN_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))) {
-        return false;
-      }
-    }
-
-    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
-
-    if (NS_WARN_IF(!Write(aCx, value))) {
-      return false;
-    }
-
-    return true;
+    return StoreConsoleData(aCx, mCallData);
   }
 
   void
   RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
              nsPIDOMWindowInner* aInnerWindow) override
   {
     AssertIsOnMainThread();
 
@@ -578,170 +854,131 @@ private:
       }
 
       mCallData->SetIDs(id, innerID);
     }
 
     // Now we could have the correct window (if we are not window-less).
     mClonedData.mParent = aInnerWindow;
 
-    ProcessCallData(aCx);
+    ProcessCallData(aCx, mConsole, mCallData);
 
     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;
-    }
-
+    ReleaseCallData(mConsole, mCallData);
     mCallData = nullptr;
   }
 
-  void
-  ProcessCallData(JSContext* aCx)
-  {
-    AssertIsOnMainThread();
-
-    ConsoleCommon::ClearException ce(aCx);
-
-    JS::Rooted<JS::Value> argumentsValue(aCx);
-    if (!Read(aCx, &argumentsValue)) {
-      return;
-    }
-
-    MOZ_ASSERT(argumentsValue.isObject());
-
-    JS::Rooted<JSObject*> argumentsObj(aCx, &argumentsValue.toObject());
-
-    uint32_t length;
-    if (!JS_GetArrayLength(aCx, argumentsObj, &length)) {
-      return;
-    }
-
-    Sequence<JS::Value> values;
-    SequenceRooter<JS::Value> arguments(aCx, &values);
-
-    for (uint32_t i = 0; i < length; ++i) {
-      JS::Rooted<JS::Value> value(aCx);
-
-      if (!JS_GetElement(aCx, argumentsObj, i, &value)) {
-        return;
-      }
-
-      if (!values.AppendElement(value, fallible)) {
-        return;
-      }
-    }
-
-    MOZ_ASSERT(values.Length() == length);
-
-    mConsole->ProcessCallData(aCx, mCallData, values);
-  }
-
   RefPtr<ConsoleCallData> mCallData;
 };
 
 // This runnable calls ProfileMethod() on the console on the main-thread.
-class ConsoleProfileRunnable final : public ConsoleRunnable
+class ConsoleProfileWorkletRunnable final : public ConsoleWorkletRunnable
 {
 public:
-  ConsoleProfileRunnable(Console* aConsole, Console::MethodName aName,
-                         const nsAString& aAction,
-                         const Sequence<JS::Value>& aArguments)
-    : ConsoleRunnable(aConsole)
+  static already_AddRefed<ConsoleProfileWorkletRunnable>
+  Create(Console* aConsole, Console::MethodName aName, const nsAString& aAction,
+         const Sequence<JS::Value>& aArguments)
+  {
+    WorkletThread::AssertIsOnWorkletThread();
+
+    RefPtr<ConsoleProfileWorkletRunnable> runnable =
+      new ConsoleProfileWorkletRunnable(aConsole, aName, aAction);
+
+    if (!runnable->StoreProfileData(WorkletThread::Get()->GetJSContext(),
+                                    aArguments)) {
+      return nullptr;
+    }
+
+    return runnable.forget();
+  }
+
+private:
+  ConsoleProfileWorkletRunnable(Console* aConsole, Console::MethodName aName,
+                                const nsAString& aAction)
+    : ConsoleWorkletRunnable(aConsole)
+    , mName(aName)
+    , mAction(aAction)
+  {
+    MOZ_ASSERT(aConsole);
+  }
+
+  void
+  RunOnMainThread() override
+  {
+    AssertIsOnMainThread();
+
+    AutoSafeJSContext cx;
+
+    JSObject* sandbox =
+      mConsole->GetOrCreateSandbox(cx,
+                                   mWorkletThread->GetWorkletLoadInfo().Principal());
+    JS::Rooted<JSObject*> global(cx, sandbox);
+    if (NS_WARN_IF(!global)) {
+      return;
+    }
+
+    // The CreateSandbox call returns a proxy to the actual sandbox object. We
+    // don't need a proxy here.
+    global = js::UncheckedUnwrap(global);
+
+    JSAutoCompartment ac(cx, global);
+
+    // We don't need to set a parent object in mCallData bacause there are not
+    // DOM objects exposed to worklet.
+
+    ProcessProfileData(cx, mConsole, mName, mAction);
+  }
+
+  virtual void
+  ReleaseData() override
+  {}
+
+  Console::MethodName mName;
+  nsString mAction;
+};
+
+// This runnable calls ProfileMethod() on the console on the main-thread.
+class ConsoleProfileWorkerRunnable final : public ConsoleWorkerRunnable
+{
+public:
+  ConsoleProfileWorkerRunnable(Console* aConsole, Console::MethodName aName,
+                               const nsAString& aAction,
+                               const Sequence<JS::Value>& aArguments)
+    : ConsoleWorkerRunnable(aConsole)
     , mName(aName)
     , mAction(aAction)
     , mArguments(aArguments)
   {
     MOZ_ASSERT(aConsole);
   }
 
 private:
   bool
   PreDispatch(JSContext* aCx) override
   {
-    ConsoleCommon::ClearException ce(aCx);
-
-    JS::Rooted<JSObject*> arguments(aCx,
-      JS_NewArrayObject(aCx, mArguments.Length()));
-    if (NS_WARN_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))) {
-        return false;
-      }
-    }
-
-    JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
-
-    if (NS_WARN_IF(!Write(aCx, value))) {
-      return false;
-    }
-
-    return true;
+    return StoreProfileData(aCx, mArguments);
   }
 
   void
   RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
              nsPIDOMWindowInner* aInnerWindow) override
   {
     AssertIsOnMainThread();
 
-    ConsoleCommon::ClearException ce(aCx);
-
     // Now we could have the correct window (if we are not window-less).
     mClonedData.mParent = aInnerWindow;
 
-    JS::Rooted<JS::Value> argumentsValue(aCx);
-    bool ok = Read(aCx, &argumentsValue);
+    ProcessProfileData(aCx, mConsole, mName, mAction);
+
     mClonedData.mParent = nullptr;
-
-    if (!ok) {
-      return;
-    }
-
-    MOZ_ASSERT(argumentsValue.isObject());
-    JS::Rooted<JSObject*> argumentsObj(aCx, &argumentsValue.toObject());
-    if (NS_WARN_IF(!argumentsObj)) {
-      return;
-    }
-
-    uint32_t length;
-    if (!JS_GetArrayLength(aCx, argumentsObj, &length)) {
-      return;
-    }
-
-    Sequence<JS::Value> arguments;
-
-    for (uint32_t i = 0; i < length; ++i) {
-      JS::Rooted<JS::Value> value(aCx);
-
-      if (!JS_GetElement(aCx, argumentsObj, i, &value)) {
-        return;
-      }
-
-      if (!arguments.AppendElement(value, fallible)) {
-        return;
-      }
-    }
-
-    mConsole->ProfileMethodInternal(aCx, mName, mAction, arguments);
   }
 
   virtual void
   ReleaseData() override
   {}
 
   Console::MethodName mName;
   nsString mAction;
@@ -791,47 +1028,67 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 /* static */ already_AddRefed<Console>
 Console::Create(JSContext* aCx, nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
 {
   MOZ_ASSERT_IF(NS_IsMainThread(), aWindow);
 
-  RefPtr<Console> console = new Console(aCx, aWindow);
+  uint64_t outerWindowID = 0;
+  uint64_t innerWindowID = 0;
+
+  if (aWindow) {
+    innerWindowID = aWindow->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 = aWindow->GetOuterWindow();
+    if (outerWindow) {
+      outerWindowID = outerWindow->WindowID();
+    }
+  }
+
+  RefPtr<Console> console = new Console(aCx, aWindow, outerWindowID, innerWindowID);
   console->Initialize(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return console.forget();
 }
 
-Console::Console(JSContext* aCx, nsPIDOMWindowInner* aWindow)
+/* static */ already_AddRefed<Console>
+Console::CreateForWorklet(JSContext* aCx, uint64_t aOuterWindowID,
+                          uint64_t aInnerWindowID, ErrorResult& aRv)
+{
+  WorkletThread::AssertIsOnWorkletThread();
+
+  RefPtr<Console> console =
+    new Console(aCx, nullptr, aOuterWindowID, aInnerWindowID);
+  console->Initialize(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return console.forget();
+}
+
+Console::Console(JSContext* aCx, nsPIDOMWindowInner* aWindow,
+                 uint64_t aOuterWindowID, uint64_t aInnerWindowID)
   : mWindow(aWindow)
-  , mOuterID(0)
-  , mInnerID(0)
+  , mOuterID(aOuterWindowID)
+  , mInnerID(aInnerWindowID)
   , mDumpToStdout(false)
   , mChromeInstance(false)
   , mMaxLogLevel(ConsoleLogLevel::All)
   , mStatus(eUnknown)
   , mCreationTimeStamp(TimeStamp::Now())
 {
-  if (mWindow) {
-    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();
-    }
-  }
-
   // Let's enable the dumping to stdout by default for chrome.
   if (nsContentUtils::ThreadsafeIsSystemCaller(aCx)) {
     mDumpToStdout = DOMPrefs::DumpEnabled();
   }
 
   mozilla::HoldJSObjects(this);
 }
 
@@ -1089,20 +1346,32 @@ Console::ProfileMethodInternal(JSContext
   }
 
   if (!ShouldProceed(aMethodName)) {
     return;
   }
 
   MaybeExecuteDumpFunction(aCx, aAction, aData, nullptr);
 
+  if (WorkletThread::IsOnWorkletThread()) {
+    RefPtr<ConsoleProfileWorkletRunnable> runnable =
+      ConsoleProfileWorkletRunnable::Create(this, aMethodName, aAction, aData);
+    if (!runnable) {
+      return;
+    }
+
+    WorkletThread::Get()->DispatchRunnable(runnable.forget());
+    return;
+  }
+
   if (!NS_IsMainThread()) {
     // Here we are in a worker thread.
-    RefPtr<ConsoleProfileRunnable> runnable =
-      new ConsoleProfileRunnable(this, aMethodName, aAction, aData);
+    RefPtr<ConsoleProfileWorkerRunnable> runnable =
+      new ConsoleProfileWorkerRunnable(this, aMethodName, aAction, aData);
+
 
     runnable->Dispatch(aCx);
     return;
   }
 
   ConsoleCommon::ClearException ce(aCx);
 
   RootedDictionary<ConsoleProfileEvent> event(aCx);
@@ -1271,16 +1540,18 @@ Console::MethodInternal(JSContext* aCx, 
           bool pb;
           if (NS_SUCCEEDED(loadContext->GetUsePrivateBrowsing(&pb))) {
             MOZ_ASSERT(pb == !!oa.mPrivateBrowsingId);
           }
         }
       }
 #endif
     }
+  } else if (WorkletThread::IsOnWorkletThread()) {
+    oa = WorkletThread::Get()->GetWorkletLoadInfo().OriginAttributesRef();
   } else {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
     oa = workerPrivate->GetOriginAttributes();
   }
 
   callData->SetOriginAttributes(oa);
 
@@ -1365,21 +1636,32 @@ Console::MethodInternal(JSContext* aCx, 
 
     // Just because we don't want to expose
     // retrieveConsoleEvents/setConsoleEventHandler to main-thread, we can
     // cleanup the mCallDataStorage:
     UnstoreCallData(callData);
     return;
   }
 
+  if (WorkletThread::IsOnWorkletThread()) {
+    RefPtr<ConsoleCallDataWorkletRunnable> runnable =
+      ConsoleCallDataWorkletRunnable::Create(this, callData);
+    if (!runnable) {
+      return;
+    }
+
+    NS_DispatchToMainThread(runnable);
+    return;
+  }
+
   // We do this only in workers for now.
   NotifyHandler(aCx, aData, callData);
 
-  RefPtr<ConsoleCallDataRunnable> runnable =
-    new ConsoleCallDataRunnable(this, callData);
+  RefPtr<ConsoleCallDataWorkerRunnable> runnable =
+    new ConsoleCallDataWorkerRunnable(this, callData);
   Unused << NS_WARN_IF(!runnable->Dispatch(aCx));
 }
 
 // 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.
 // The second slot is a PrivateValue() holding an nsIStackFrame* when we haven't
 // reified the stack yet, or an UndefinedValue() otherwise.
@@ -2263,17 +2545,18 @@ Console::StoreCallData(ConsoleCallData* 
 
   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.
+    // until the pending operation (ConsoleCallDataWorkerRunnable or
+    // ConsoleCallDataWorkletRunnable) is completed.
     if (callData->mStatus == ConsoleCallData::eInUse) {
       callData->mStatus = ConsoleCallData::eToBeDeleted;
       mCallDataStoragePending.AppendElement(callData);
     }
   }
 }
 
 void
@@ -2424,17 +2707,17 @@ Console::GetConsoleInternal(const Global
 {
   // Window
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindowInner> innerWindow =
       do_QueryInterface(aGlobal.GetAsSupports());
 
     // we are probably running a chrome script.
     if (!innerWindow) {
-      RefPtr<Console> console = new Console(aGlobal.Context(), nullptr);
+      RefPtr<Console> console = new Console(aGlobal.Context(), nullptr, 0, 0);
       console->Initialize(aRv);
       if (NS_WARN_IF(aRv.Failed())) {
         return nullptr;
       }
 
       return console.forget();
     }
 
@@ -2543,16 +2826,21 @@ Console::MonotonicTimer(JSContext* aCx, 
     return true;
   }
 
   if (NS_IsMainThread()) {
     *aTimeStamp = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
     return true;
   }
 
+  if (WorkletThread::IsOnWorkletThread()) {
+    *aTimeStamp = WorkletThread::Get()->TimeStampToDOMHighRes(TimeStamp::Now());
+    return true;
+  }
+
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
   *aTimeStamp = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
   return true;
 }
 
 /* static */ already_AddRefed<ConsoleInstance>
--- a/dom/console/Console.h
+++ b/dom/console/Console.h
@@ -39,16 +39,20 @@ class Console final : public nsIObserver
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
   NS_DECL_NSIOBSERVER
 
   static already_AddRefed<Console>
   Create(JSContext* aCx, nsPIDOMWindowInner* aWindow, ErrorResult& aRv);
 
+  static already_AddRefed<Console>
+  CreateForWorklet(JSContext* aCx, uint64_t aOuterWindowID,
+                   uint64_t aInnerWindowID, ErrorResult& aRv);
+
   // WebIDL methods
   nsPIDOMWindowInner* GetParentObject() const
   {
     return mWindow;
   }
 
   static void
   Log(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
@@ -124,17 +128,18 @@ public:
   void
   RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
                         ErrorResult& aRv);
 
   void
   SetConsoleEventHandler(AnyCallback* aHandler);
 
 private:
-  Console(JSContext* aCx, nsPIDOMWindowInner* aWindow);
+  Console(JSContext* aCx, nsPIDOMWindowInner* aWindow,
+          uint64_t aOuterWindowID, uint64_t aInnerWIndowID);
   ~Console();
 
   void
   Initialize(ErrorResult& aRv);
 
   void
   Shutdown();
 
@@ -458,18 +463,20 @@ private:
     eShuttingDown
   } mStatus;
 
   // This is used when Console is created and it's used only for JSM custom
   // console instance.
   mozilla::TimeStamp mCreationTimeStamp;
 
   friend class ConsoleCallData;
+  friend class ConsoleCallDataWorkletRunnable;
   friend class ConsoleInstance;
+  friend class ConsoleProfileWorkerRunnable;
+  friend class ConsoleProfileWorkletRunnable;
   friend class ConsoleRunnable;
-  friend class ConsoleCallDataRunnable;
-  friend class ConsoleProfileRunnable;
+  friend class ConsoleWorkerRunnable;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_Console_h */
--- a/dom/console/ConsoleInstance.cpp
+++ b/dom/console/ConsoleInstance.cpp
@@ -75,17 +75,17 @@ WebIDLevelToConsoleUtilsLevel(ConsoleLev
 
   return ConsoleUtils::eLog;
 }
 
 } // anonymous
 
 ConsoleInstance::ConsoleInstance(JSContext* aCx,
                                  const ConsoleInstanceOptions& aOptions)
-  : mConsole(new Console(aCx, nullptr))
+  : mConsole(new Console(aCx, nullptr, 0, 0))
 {
   mConsole->mConsoleID = aOptions.mConsoleID;
   mConsole->mPassedInnerID = aOptions.mInnerID;
 
   if (aOptions.mDump.WasPassed()) {
     mConsole->mDumpFunction = &aOptions.mDump.Value();
   }
 
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -6,16 +6,17 @@
 
 #include "Worklet.h"
 #include "WorkletThread.h"
 #include "AudioWorkletGlobalScope.h"
 #include "PaintWorkletGlobalScope.h"
 
 #include "mozilla/dom/WorkletBinding.h"
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/RegisterWorkletBindings.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "nsIInputStreamPump.h"
 #include "nsIThreadRetargetableRequest.h"
@@ -24,17 +25,18 @@
 
 namespace mozilla {
 namespace dom {
 
 class ExecutionRunnable final : public Runnable
 {
 public:
   ExecutionRunnable(WorkletFetchHandler* aHandler, Worklet::WorkletType aType,
-                    char16_t* aScriptBuffer, size_t aScriptLength)
+                    char16_t* aScriptBuffer, size_t aScriptLength,
+                    const WorkletLoadInfo& aWorkletLoadInfo)
     : Runnable("Worklet::ExecutionRunnable")
     , mHandler(aHandler)
     , mWorkletType(aType)
     , mBuffer(aScriptBuffer, aScriptLength,
               JS::SourceBufferHolder::GiveOwnership)
     , mResult(NS_ERROR_FAILURE)
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -217,17 +219,17 @@ public:
     if (NS_WARN_IF(NS_FAILED(rv))) {
       RejectPromises(rv);
       return NS_OK;
     }
 
     // Moving the ownership of the buffer
     nsCOMPtr<nsIRunnable> runnable =
       new ExecutionRunnable(this, mWorklet->Type(), scriptTextBuf,
-                            scriptTextLength);
+                            scriptTextLength, mWorklet->LoadInfo());
 
     RefPtr<WorkletThread> thread = mWorklet->GetOrCreateThread();
     if (!thread) {
       RejectPromises(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
     if (NS_FAILED(thread->DispatchRunnable(runnable.forget()))) {
@@ -420,16 +422,29 @@ ExecutionRunnable::RunOnMainThread()
     mHandler->ExecutionFailed(mResult);
     return;
   }
 
   mHandler->ExecutionSucceeded();
 }
 
 // ---------------------------------------------------------------------------
+// WorkletLoadInfo
+
+WorkletLoadInfo::WorkletLoadInfo()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+WorkletLoadInfo::~WorkletLoadInfo()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+// ---------------------------------------------------------------------------
 // Worklet
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Worklet)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Worklet)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   tmp->TerminateThread();
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -447,26 +462,43 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(Worklet
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Worklet)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Worklet::Worklet(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal,
                  WorkletType aWorkletType)
   : mWindow(aWindow)
-  , mPrincipal(aPrincipal)
   , mWorkletType(aWorkletType)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(NS_IsMainThread());
 
 #ifdef RELEASE_OR_BETA
   MOZ_CRASH("This code should not go to release/beta yet!");
 #endif
+
+  // Reset mWorkletLoadInfo and populate it.
+
+  memset(&mWorkletLoadInfo, 0, sizeof(WorkletLoadInfo));
+
+  mWorkletLoadInfo.mInnerWindowID = aWindow->WindowID();
+
+  nsPIDOMWindowOuter* outerWindow = aWindow->GetOuterWindow();
+  if (outerWindow) {
+    mWorkletLoadInfo.mOuterWindowID = outerWindow->WindowID();
+  }
+
+  mWorkletLoadInfo.mOriginAttributes =
+    BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
+
+  mWorkletLoadInfo.mPrincipal = aPrincipal;
+
+  mWorkletLoadInfo.mDumpEnabled = DOMPrefs::DumpEnabled();
 }
 
 Worklet::~Worklet()
 {
   TerminateThread();
 }
 
 JSObject*
@@ -535,28 +567,29 @@ Worklet::AddImportFetchHandler(const nsA
 
 WorkletThread*
 Worklet::GetOrCreateThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mWorkletThread) {
     // Thread creation. FIXME: this will change.
-    mWorkletThread = WorkletThread::Create();
+    mWorkletThread = WorkletThread::Create(mWorkletLoadInfo);
   }
 
   return mWorkletThread;
 }
 
 void
 Worklet::TerminateThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mWorkletThread) {
     return;
   }
 
   mWorkletThread->Terminate();
   mWorkletThread = nullptr;
+  mWorkletLoadInfo.mPrincipal = nullptr;
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/worklet/Worklet.h
+++ b/dom/worklet/Worklet.h
@@ -3,33 +3,67 @@
 /* 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_dom_Worklet_h
 #define mozilla_dom_Worklet_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/ErrorResult.h"
 #include "nsRefPtrHashtable.h"
 #include "nsWrapperCache.h"
 #include "nsCOMPtr.h"
 
 class nsPIDOMWindowInner;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
+class Worklet;
 class WorkletFetchHandler;
 class WorkletGlobalScope;
 class WorkletThread;
 enum class CallerType : uint32_t;
 
+class WorkletLoadInfo
+{
+public:
+  WorkletLoadInfo();
+  ~WorkletLoadInfo();
+
+  uint64_t OuterWindowID() const { return mOuterWindowID; }
+  uint64_t InnerWindowID() const { return mInnerWindowID; }
+  bool DumpEnabled() const { return mDumpEnabled; }
+
+  const OriginAttributes& OriginAttributesRef() const
+  {
+    return mOriginAttributes;
+  }
+
+  nsIPrincipal* Principal() const
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    return mPrincipal;
+  }
+
+private:
+  uint64_t mOuterWindowID;
+  uint64_t mInnerWindowID;
+  bool mDumpEnabled;
+  OriginAttributes mOriginAttributes;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+
+  friend class Worklet;
+  friend class WorkletThread;
+};
+
 class Worklet final : public nsISupports
                     , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Worklet)
 
   enum WorkletType {
@@ -58,36 +92,43 @@ public:
   }
 
   static already_AddRefed<WorkletGlobalScope>
   CreateGlobalScope(JSContext* aCx, WorkletType aWorkletType);
 
   WorkletThread*
   GetOrCreateThread();
 
+  const WorkletLoadInfo&
+  LoadInfo() const
+  {
+    return mWorkletLoadInfo;
+  }
+
 private:
   ~Worklet();
 
   WorkletFetchHandler*
   GetImportFetchHandler(const nsACString& aURI);
 
   void
   AddImportFetchHandler(const nsACString& aURI, WorkletFetchHandler* aHandler);
 
   void
   TerminateThread();
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
-  nsCOMPtr<nsIPrincipal> mPrincipal;
 
   WorkletType mWorkletType;
 
   nsRefPtrHashtable<nsCStringHashKey, WorkletFetchHandler> mImportHandlers;
 
   RefPtr<WorkletThread> mWorkletThread;
 
+  WorkletLoadInfo mWorkletLoadInfo;
+
   friend class WorkletFetchHandler;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Worklet_h
--- a/dom/worklet/WorkletGlobalScope.cpp
+++ b/dom/worklet/WorkletGlobalScope.cpp
@@ -2,17 +2,16 @@
 /* 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 "WorkletGlobalScope.h"
 #include "mozilla/dom/WorkletGlobalScopeBinding.h"
 #include "mozilla/dom/Console.h"
-#include "mozilla/dom/DOMPrefs.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkletGlobalScope)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkletGlobalScope)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -45,33 +44,43 @@ WorkletGlobalScope::WrapObject(JSContext
 {
   MOZ_CRASH("We should never get here!");
   return nullptr;
 }
 
 already_AddRefed<Console>
 WorkletGlobalScope::GetConsole(JSContext* aCx, ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_FAILURE);
-/* TODO
+  RefPtr<WorkletThread> thread = WorkletThread::Get();
+  MOZ_ASSERT(thread);
+
   if (!mConsole) {
-    mConsole = Console::CreateForWorklet(aCx, aRv);
+    mConsole =
+      Console::CreateForWorklet(aCx,
+                                thread->GetWorkletLoadInfo().OuterWindowID(),
+                                thread->GetWorkletLoadInfo().InnerWindowID(),
+                                aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
-  } */
+  }
 
   RefPtr<Console> console = mConsole;
   return console.forget();
 }
 
 void
 WorkletGlobalScope::Dump(const Optional<nsAString>& aString) const
 {
-  if (!DOMPrefs::DumpEnabled()) {
+  WorkletThread::AssertIsOnWorkletThread();
+
+  WorkletThread* workletThread = WorkletThread::Get();
+  MOZ_ASSERT(workletThread);
+
+  if (!workletThread->GetWorkletLoadInfo().DumpEnabled()) {
     return;
   }
 
   if (!aString.WasPassed()) {
     return;
   }
 
   NS_ConvertUTF16toUTF8 str(aString.Value());
--- a/dom/worklet/WorkletThread.cpp
+++ b/dom/worklet/WorkletThread.cpp
@@ -22,17 +22,17 @@ namespace {
 // The size of the generational GC nursery for worklet, in bytes.
 #define WORKLET_DEFAULT_NURSERY_SIZE 1 * 1024 * 1024
 
 // The C stack size. We use the same stack size on all platforms for
 // consistency.
 const uint32_t kWorkletStackSize = 256 * sizeof(size_t) * 1024;
 
 // This class is allocated per thread and can be retrieved from CC.
-// It's used to get the current WorketThread object.
+// It's used to get the current WorkletThread object.
 class WorkletThreadContextPrivate : private PerThreadAtomCache
 {
 public:
   explicit
   WorkletThreadContextPrivate(WorkletThread* aWorkletThread)
     : mWorkletThread(aWorkletThread)
   {
     MOZ_ASSERT(!NS_IsMainThread());
@@ -278,35 +278,38 @@ public:
     mWorkletThread->TerminateInternal();
     return NS_OK;
   }
 
 private:
   RefPtr<WorkletThread> mWorkletThread;
 };
 
-WorkletThread::WorkletThread()
+WorkletThread::WorkletThread(const WorkletLoadInfo& aWorkletLoadInfo)
   : nsThread(MakeNotNull<ThreadEventQueue<mozilla::EventQueue>*>(
                MakeUnique<mozilla::EventQueue>()),
              nsThread::NOT_MAIN_THREAD, kWorkletStackSize)
+  , mWorkletLoadInfo(aWorkletLoadInfo)
+  , mCreationTimeStamp(TimeStamp::Now())
   , mJSContext(nullptr)
 {
 }
 
 WorkletThread::~WorkletThread()
 {
   // This should be gone during the termination step.
   MOZ_ASSERT(!mJSContext);
 }
 
 // static
 already_AddRefed<WorkletThread>
-WorkletThread::Create()
+WorkletThread::Create(const WorkletLoadInfo& aWorkletLoadInfo)
 {
-  RefPtr<WorkletThread> thread = new WorkletThread();
+  RefPtr<WorkletThread> thread =
+    new WorkletThread(aWorkletLoadInfo);
   if (NS_WARN_IF(NS_FAILED(thread->Init()))) {
     return nullptr;
   }
 
   RefPtr<PrimaryRunnable> runnable = new PrimaryRunnable(thread);
   if (NS_WARN_IF(NS_FAILED(thread->DispatchRunnable(runnable.forget())))) {
     return nullptr;
   }
@@ -411,16 +414,22 @@ WorkletThread::TerminateInternal()
 JSContext*
 WorkletThread::GetJSContext() const
 {
   AssertIsOnWorkletThread();
   MOZ_ASSERT(mJSContext);
   return mJSContext;
 }
 
+const WorkletLoadInfo&
+WorkletThread::GetWorkletLoadInfo() const
+{
+  return mWorkletLoadInfo;
+}
+
 /* static */ bool
 WorkletThread::IsOnWorkletThread()
 {
   const char* threadName = PR_GetThreadName(PR_GetCurrentThread());
   return threadName && !strcmp(threadName, "worklet");
 }
 
 /* static */ void
--- a/dom/worklet/WorkletThread.h
+++ b/dom/worklet/WorkletThread.h
@@ -4,56 +4,69 @@
  * 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_dom_worklet_WorkletThread_h
 #define mozilla_dom_worklet_WorkletThread_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CondVar.h"
+#include "mozilla/dom/Worklet.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
+#include "mozilla/TimeStamp.h"
 #include "nsThread.h"
 
 class nsIRunnable;
 
 namespace mozilla {
 namespace dom {
 
 class WorkletThread final : public nsThread
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   static already_AddRefed<WorkletThread>
-  Create();
+  Create(const WorkletLoadInfo& aWorkletLoadInfo);
 
   static WorkletThread*
   Get();
 
   static bool
   IsOnWorkletThread();
 
   static void
   AssertIsOnWorkletThread();
 
   static JSPrincipals*
   GetWorkerPrincipal();
 
   JSContext*
   GetJSContext() const;
 
+  const WorkletLoadInfo&
+  GetWorkletLoadInfo() const;
+
   nsresult
   DispatchRunnable(already_AddRefed<nsIRunnable> aRunnable);
 
   void
   Terminate();
 
+  DOMHighResTimeStamp
+  TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const
+  {
+    MOZ_ASSERT(!aTimeStamp.IsNull());
+    TimeDuration duration = aTimeStamp - mCreationTimeStamp;
+    return duration.ToMilliseconds();
+  }
+
 private:
-  WorkletThread();
+  explicit WorkletThread(const WorkletLoadInfo& aWorkletLoadInfo);
   ~WorkletThread();
 
   void
   RunEventLoop(JSRuntime* aParentRuntime);
   class PrimaryRunnable;
 
   void
   TerminateInternal();
@@ -65,16 +78,19 @@ private:
   Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags) override;
 
   NS_IMETHOD
   DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
 
   NS_IMETHOD
   DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) override;
 
+  const WorkletLoadInfo mWorkletLoadInfo;
+  TimeStamp mCreationTimeStamp;
+
   // Touched only on the worklet thread. This is a raw pointer because it's set
   // and nullified by RunEventLoop().
   JSContext* mJSContext;
 };
 
 } // namespace dom
 } // namespace mozilla