mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
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:
+153
-120
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user