import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1044102 - Part 0 - Test cases. r=smaug. (e588558b1)
- Bug 1044102 - Part 1 - Implement ImageBitmap. r=roc, sr=smaug (17702ab3c)
- Bug 1044102 - Part 2 - Support ImageBitmap as CanvasImageSource. r=smaug (b9454bbe3)
- Bug 1049091 - Console API in workers should not block the script waiting for the main-thread, r=ehsan (08a18bdd5)
- Bug 1154076 - Console API must keep the Worker alive when the runnable to the main-thread is dispatched, r=bent (67ca7f850)
- Bug 1184541 - Create a StructuredCloneHelperInternal and use it in the Console API, r=smaug (45391c7d9)
- fix namespace (808e6e99d)
- Bug 1184557 - part 1 - StructuredCloneHelper class for window to window postMessage, r=smaug (19df45161)
- Bug 1184557 - part 2 - StructuredCloneHelperInternal::Shutdown, r=smaug (a157c50d0)
- Bug 1184995 - StructuredCloneHelper for BroadcastChannel and DataStore, r=smaug (86f901c2f)
- namespace fix (a9f89ad33)
- Bug 1185569 - Use StructuredCloneHelper in MessagePort, r=smaug (c26235044)
- Bug 1188265 - No manual JS_ClearPendingException when StructuredCloneHelper is used, r=smaug (1e9fbe26f)
This commit is contained in:
2021-09-07 11:04:19 +08:00
parent d43e6f58e1
commit 88786f232f
50 changed files with 3573 additions and 986 deletions
+153 -120
View File
@@ -10,6 +10,7 @@
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/Maybe.h"
#include "nsCycleCollectionParticipant.h"
@@ -24,6 +25,7 @@
#include "xpcprivate.h"
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsProxyRelease.h"
#include "nsIConsoleAPIStorage.h"
#include "nsIDOMWindowUtils.h"
@@ -69,90 +71,11 @@ ConsoleStructuredCloneData
* It's not the best, but at least we are able to show something.
*/
// This method is called by the Structured Clone Algorithm when some data has
// to be read.
static JSObject*
ConsoleStructuredCloneCallbacksRead(JSContext* aCx,
JSStructuredCloneReader* /* unused */,
uint32_t aTag, uint32_t aIndex,
void* aClosure)
{
AssertIsOnMainThread();
ConsoleStructuredCloneData* data =
static_cast<ConsoleStructuredCloneData*>(aClosure);
MOZ_ASSERT(data);
if (aTag == CONSOLE_TAG_BLOB) {
MOZ_ASSERT(data->mBlobs.Length() > aIndex);
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob =
Blob::Create(data->mParent, data->mBlobs.ElementAt(aIndex));
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
}
MOZ_CRASH("No other tags are supported.");
return nullptr;
}
// This method is called by the Structured Clone Algorithm when some data has
// to be written.
static bool
ConsoleStructuredCloneCallbacksWrite(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj,
void* aClosure)
{
ConsoleStructuredCloneData* data =
static_cast<ConsoleStructuredCloneData*>(aClosure);
MOZ_ASSERT(data);
nsRefPtr<Blob> blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
blob->Impl()->MayBeClonedToOtherThreads()) {
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mBlobs.Length())) {
return false;
}
data->mBlobs.AppendElement(blob->Impl());
return true;
}
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
if (!jsString) {
return false;
}
if (!JS_WriteString(aWriter, jsString)) {
return false;
}
return true;
}
static void
ConsoleStructuredCloneCallbacksError(JSContext* /* aCx */,
uint32_t /* aErrorId */)
{
NS_WARNING("Failed to clone data for the Console API in workers.");
}
static const JSStructuredCloneCallbacks gConsoleCallbacks = {
ConsoleStructuredCloneCallbacksRead,
ConsoleStructuredCloneCallbacksWrite,
ConsoleStructuredCloneCallbacksError
};
class ConsoleCallData final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ConsoleCallData)
ConsoleCallData()
: mMethodName(Console::MethodLog)
, mPrivate(false)
@@ -241,6 +164,10 @@ public:
Maybe<ConsoleStackEntry> mTopStackFrame;
Maybe<nsTArray<ConsoleStackEntry>> mReifiedStack;
nsCOMPtr<nsIStackFrame> mStack;
private:
~ConsoleCallData()
{ }
};
// This class is used to clear any exception at the end of this method.
@@ -262,6 +189,8 @@ private:
};
class ConsoleRunnable : public nsRunnable
, public WorkerFeature
, public StructuredCloneHelperInternal
{
public:
explicit ConsoleRunnable(Console* aConsole)
@@ -274,6 +203,8 @@ public:
virtual
~ConsoleRunnable()
{
// Shutdown the StructuredCloneHelperInternal class.
Shutdown();
}
bool
@@ -287,16 +218,19 @@ public:
return false;
}
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this))) {
JS_ReportError(cx,
"Failed to dispatch to main thread for the Console API!");
if (NS_WARN_IF(!mWorkerPrivate->AddFeature(cx, this))) {
return false;
}
return syncLoop.Run();
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
return true;
}
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
{
// We don't care about the notification. We just want to keep the
// mWorkerPrivate alive.
return true;
}
private:
@@ -317,17 +251,47 @@ private:
RunWithWindow(window);
}
nsRefPtr<MainThreadStopSyncLoopRunnable> response =
new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
mSyncLoopTarget.forget(),
true);
if (!response->Dispatch(nullptr)) {
NS_WARNING("Failed to dispatch response!");
}
PostDispatch();
return NS_OK;
}
void
PostDispatch()
{
class ConsoleReleaseRunnable final : public MainThreadWorkerControlRunnable
{
nsRefPtr<ConsoleRunnable> mRunnable;
public:
ConsoleReleaseRunnable(WorkerPrivate* aWorkerPrivate,
ConsoleRunnable* aRunnable)
: MainThreadWorkerControlRunnable(aWorkerPrivate)
, mRunnable(aRunnable)
{
MOZ_ASSERT(aRunnable);
}
virtual bool
WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
aWorkerPrivate->RemoveFeature(aCx, mRunnable);
mRunnable->mConsole = nullptr;
return true;
}
private:
~ConsoleReleaseRunnable()
{}
};
nsRefPtr<WorkerControlRunnable> runnable =
new ConsoleReleaseRunnable(mWorkerPrivate, this);
runnable->Dispatch(nullptr);
}
void
RunWithWindow(nsPIDOMWindow* aWindow)
{
@@ -386,14 +350,67 @@ protected:
RunConsole(JSContext* aCx, nsPIDOMWindow* aOuterWindow,
nsPIDOMWindow* aInnerWindow) = 0;
virtual JSObject* ReadCallback(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);
{
nsRefPtr<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 WriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) override
{
nsRefPtr<Blob> blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) &&
blob->Impl()->MayBeClonedToOtherThreads()) {
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB,
mClonedData.mBlobs.Length())) {
return false;
}
mClonedData.mBlobs.AppendElement(blob->Impl());
return true;
}
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
if (!jsString) {
return false;
}
if (!JS_WriteString(aWriter, jsString)) {
return false;
}
return true;
}
WorkerPrivate* mWorkerPrivate;
// Raw pointer because this method is async and this object is kept alive by
// the caller.
Console* mConsole;
// This must be released on the worker thread.
nsRefPtr<Console> mConsole;
private:
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
ConsoleStructuredCloneData mClonedData;
};
// This runnable appends a CallData object into the Console queue running on
@@ -409,7 +426,30 @@ public:
private:
~ConsoleCallDataRunnable()
{ }
{
class ReleaseCallData final : public nsRunnable
{
public:
explicit ReleaseCallData(nsRefPtr<ConsoleCallData>& aCallData)
{
mCallData.swap(aCallData);
}
NS_IMETHOD Run() override
{
mCallData = nullptr;
return NS_OK;
}
private:
nsRefPtr<ConsoleCallData> mCallData;
};
nsRefPtr<ReleaseCallData> runnable = new ReleaseCallData(mCallData);
if(NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_WARNING("Failed to dispatch a ReleaseCallData runnable. Leaking.");
}
}
bool
PreDispatch(JSContext* aCx) override
@@ -435,7 +475,7 @@ private:
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mData)) {
if (!Write(aCx, value)) {
return false;
}
@@ -473,12 +513,12 @@ private:
}
// Now we could have the correct window (if we are not window-less).
mData.mParent = aInnerWindow;
mClonedData.mParent = aInnerWindow;
ProcessCallData(aCx);
mCallData->CleanupJSObjects();
mData.mParent = nullptr;
mClonedData.mParent = nullptr;
}
private:
@@ -488,7 +528,7 @@ private:
ClearException ce(aCx);
JS::Rooted<JS::Value> argumentsValue(aCx);
if (!mArguments.read(aCx, &argumentsValue, &gConsoleCallbacks, &mData)) {
if (!Read(aCx, &argumentsValue)) {
return;
}
@@ -517,10 +557,7 @@ private:
mConsole->ProcessCallData(mCallData);
}
ConsoleCallData* mCallData;
JSAutoStructuredCloneBuffer mArguments;
ConsoleStructuredCloneData mData;
nsRefPtr<ConsoleCallData> mCallData;
};
// This runnable calls ProfileMethod() on the console on the main-thread.
@@ -565,10 +602,11 @@ private:
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
if (!mBuffer.write(aCx, value, &gConsoleCallbacks, &mData)) {
if (!Write(aCx, value)) {
return false;
}
mArguments.Clear();
return true;
}
@@ -579,11 +617,11 @@ private:
ClearException ce(aCx);
// Now we could have the correct window (if we are not window-less).
mData.mParent = aInnerWindow;
mClonedData.mParent = aInnerWindow;
JS::Rooted<JS::Value> argumentsValue(aCx);
bool ok = mBuffer.read(aCx, &argumentsValue, &gConsoleCallbacks, &mData);
mData.mParent = nullptr;
bool ok = Read(aCx, &argumentsValue);
mClonedData.mParent = nullptr;
if (!ok) {
return;
@@ -617,9 +655,6 @@ private:
nsString mAction;
Sequence<JS::Value> mArguments;
JSAutoStructuredCloneBuffer mBuffer;
ConsoleStructuredCloneData mData;
};
NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
@@ -1000,7 +1035,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
const nsAString& aMethodString,
const Sequence<JS::Value>& aData)
{
nsAutoPtr<ConsoleCallData> callData(new ConsoleCallData());
nsRefPtr<ConsoleCallData> callData(new ConsoleCallData());
ClearException ce(aCx);
@@ -1137,8 +1172,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
return;
}
// Note: we can pass the reference of callData because this runnable calls
// ProcessCallData() synchronously.
nsRefPtr<ConsoleCallDataRunnable> runnable =
new ConsoleCallDataRunnable(this, callData);
runnable->Dispatch();