--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -308,32 +308,387 @@ public:
{
JS_ClearPendingException(mCx);
}
private:
JSContext* mCx;
};
-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)
+ {
+ 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;
+ }
+
+ aCallData->mStatus = ConsoleCallData::eInUse;
+ return true;
+ }
+
+ void
+ ProcessCallData(JSContext* aCx, Console* aConsole, ConsoleCallData* aCallData)
+ {
+ AssertIsOnMainThread();
+
+ 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)
+ {
+ 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,
+ const nsAString& aAction)
+ {
+ AssertIsOnMainThread();
+
+ 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());
+
+ 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, aAction, arguments);
+ }
+
+ ConsoleStructuredCloneData mClonedData;
+};
+
+class ConsoleWorkletRunnable : public Runnable
+ , public ConsoleRunnable
+{
+protected:
+ explicit ConsoleWorkletRunnable(Console* aConsole)
+ : 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();
+ }
+
+ ~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;
@@ -437,133 +792,47 @@ 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();
}
private:
- ~ConsoleCallDataRunnable()
+ ~ConsoleCallDataWorkerRunnable()
{
MOZ_ASSERT(!mCallData);
}
bool
PreDispatch(JSContext* aCx) override
{
- mWorkerPrivate->AssertIsOnWorkerThread();
- mCallData->AssertIsOnOwningThread();
-
- 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;
- }
-
- mCallData->mStatus = ConsoleCallData::eInUse;
- return true;
+ return StoreConsoleData(aCx, mCallData);
}
void
RunConsole(JSContext* aCx, nsPIDOMWindowOuter* aOuterWindow,
nsPIDOMWindowInner* aInnerWindow) override
{
AssertIsOnMainThread();
@@ -592,168 +861,126 @@ 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();
-
- 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, const nsAString& aAction,
- const Sequence<JS::Value>& aArguments)
- : ConsoleRunnable(aConsole)
+ static already_AddRefed<ConsoleProfileWorkletRunnable>
+ Create(Console* aConsole, const nsAString& aAction,
+ const Sequence<JS::Value>& aArguments)
+ {
+ WorkletThread::AssertIsOnWorkletThread();
+
+ RefPtr<ConsoleProfileWorkletRunnable> runnable =
+ new ConsoleProfileWorkletRunnable(aConsole, aAction);
+
+ if (!runnable->StoreProfileData(WorkletThread::Get()->GetJSContext(),
+ aArguments)) {
+ return nullptr;
+ }
+
+ return runnable.forget();
+ }
+
+private:
+ ConsoleProfileWorkletRunnable(Console* aConsole, const nsAString& aAction)
+ : ConsoleWorkletRunnable(aConsole)
+ , 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, mAction);
+ }
+
+ virtual void
+ ReleaseData() override
+ {}
+
+ nsString mAction;
+};
+
+// This runnable calls ProfileMethod() on the console on the main-thread.
+class ConsoleProfileWorkerRunnable final : public ConsoleWorkerRunnable
+{
+public:
+ ConsoleProfileWorkerRunnable(Console* aConsole, const nsAString& aAction,
+ const Sequence<JS::Value>& aArguments)
+ : ConsoleWorkerRunnable(aConsole)
, mAction(aAction)
, mArguments(aArguments)
{
MOZ_ASSERT(aConsole);
}
private:
bool
PreDispatch(JSContext* aCx) override
{
- 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();
- 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, 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, mAction, arguments);
}
virtual void
ReleaseData() override
{}
nsString mAction;
@@ -800,46 +1027,64 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
/* static */ already_AddRefed<Console>
Console::Create(nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
{
MOZ_ASSERT_IF(NS_IsMainThread(), aWindow);
- RefPtr<Console> console = new Console(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(aWindow, outerWindowID, innerWindowID);
console->Initialize(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return console.forget();
}
-Console::Console(nsPIDOMWindowInner* aWindow)
+/* static */ already_AddRefed<Console>
+Console::CreateForWorklet(uint64_t aOuterWindowID, uint64_t aInnerWindowID,
+ ErrorResult& aRv)
+{
+ WorkletThread::AssertIsOnWorkletThread();
+
+ RefPtr<Console> console =
+ new Console(nullptr, aOuterWindowID, aInnerWindowID);
+ console->Initialize(aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ return console.forget();
+}
+
+Console::Console(nsPIDOMWindowInner* aWindow, uint64_t aOuterWindowID,
+ uint64_t aInnerWindowID)
: mWindow(aWindow)
- , mOuterID(0)
- , mInnerID(0)
+ , mOuterID(aOuterWindowID)
+ , mInnerID(aInnerWindowID)
, mStatus(eUnknown)
{
MOZ_ASSERT_IF(NS_IsMainThread(), aWindow);
-
- 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();
- }
- }
-
mozilla::HoldJSObjects(this);
}
Console::~Console()
{
AssertIsOnOwningThread();
Shutdown();
mozilla::DropJSObjects(this);
@@ -1056,20 +1301,31 @@ void
Console::ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
const Sequence<JS::Value>& aData)
{
// Make all Console API no-op if DevTools aren't enabled.
if (!nsContentUtils::DevToolsEnabled(aCx)) {
return;
}
+ if (WorkletThread::IsOnWorkletThread()) {
+ RefPtr<ConsoleProfileWorkletRunnable> runnable =
+ ConsoleProfileWorkletRunnable::Create(this, 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, aAction, aData);
+ RefPtr<ConsoleProfileWorkerRunnable> runnable =
+ new ConsoleProfileWorkerRunnable(this, aAction, aData);
runnable->Dispatch(aCx);
return;
}
ClearException ce(aCx);
RootedDictionary<ConsoleProfileEvent> event(aCx);
@@ -1221,17 +1477,19 @@ Console::MethodInternal(JSContext* aCx,
if (NS_WARN_IF(!callData->Initialize(aCx, aMethodName, aMethodString,
aData, this))) {
return;
}
OriginAttributes oa;
- if (mWindow) {
+ if (NS_IsMainThread()) {
+ MOZ_ASSERT(mWindow);
+
// Save the principal's OriginAttributes in the console event data
// so that we will be able to filter messages by origin attributes.
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
if (NS_WARN_IF(!sop)) {
return;
}
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
@@ -1251,16 +1509,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);
@@ -1343,16 +1603,19 @@ Console::MethodInternal(JSContext* aCx,
return;
}
timelines->AddMarkerForDocShell(docShell, Move(
MakeUnique<ConsoleTimelineMarker>(
key, aMethodName == MethodTime ? MarkerTracingType::START
: MarkerTracingType::END)));
}
+ } else if (WorkletThread::IsOnWorkletThread()) {
+ monotonicTimer =
+ WorkletThread::Get()->TimeStampToDOMHighRes(TimeStamp::Now());
} else {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
monotonicTimer = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
}
}
@@ -1383,21 +1646,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.
@@ -2283,17 +2557,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