Bug 1328964 - part 3 - Console API exposed to worklets r=baku
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 12 Apr 2018 16:21:20 +1200
changeset 412931 bdd4af79d6f765e6071f67f39bea4c84085acb51
parent 412930 16197254fa363db0fba9aae4211ff0e78733c2c7
child 412932 608bd57e774e5b1ee466c41ce7343d3282d75428
push id62543
push userktomlinson@mozilla.com
push dateThu, 12 Apr 2018 07:20:04 +0000
treeherderautoland@860e07a126c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1328964
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1328964 - part 3 - Console API exposed to worklets r=baku 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