Bug 1184995 - StructuredCloneHelper for BroadcastChannel and DataStore, r=smaug

This commit is contained in:
Andrea Marchesini 2015-07-28 08:38:16 +01:00
parent 74ad9a8c6b
commit d5fb31ae84
9 changed files with 236 additions and 171 deletions

View File

@ -21,30 +21,6 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(FileList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FileList)
/* static */ already_AddRefed<FileList>
FileList::Create(nsISupports* aParent, FileListClonedData* aData)
{
MOZ_ASSERT(aData);
nsRefPtr<FileList> fileList = new FileList(aParent);
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aData->BlobImpls();
for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
const nsRefPtr<BlobImpl>& blobImpl = blobImpls[i];
MOZ_ASSERT(blobImpl);
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file = File::Create(aParent, blobImpl);
MOZ_ASSERT(file);
if (NS_WARN_IF(!fileList->Append(file))) {
return nullptr;
}
}
return fileList.forget();
}
JSObject*
FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
@ -67,19 +43,5 @@ FileList::Item(uint32_t aIndex, nsISupports** aFile)
return NS_OK;
}
already_AddRefed<FileListClonedData>
FileList::CreateClonedData() const
{
nsTArray<nsRefPtr<BlobImpl>> blobImpls;
for (uint32_t i = 0; i < mFiles.Length(); ++i) {
blobImpls.AppendElement(mFiles[i]->Impl());
}
nsRefPtr<FileListClonedData> data = new FileListClonedData(blobImpls);
return data.forget();
}
NS_IMPL_ISUPPORTS0(FileListClonedData)
} // namespace dom
} // namespace mozilla

View File

@ -7,6 +7,8 @@
#ifndef mozilla_dom_FileList_h
#define mozilla_dom_FileList_h
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMFileList.h"
#include "nsWrapperCache.h"
@ -16,27 +18,6 @@ namespace dom {
class BlobImpls;
class File;
class FileListClonedData final : public nsISupports
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
explicit FileListClonedData(const nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls)
: mBlobImpls(aBlobImpls)
{}
const nsTArray<nsRefPtr<BlobImpl>>& BlobImpls() const
{
return mBlobImpls;
}
private:
~FileListClonedData()
{}
const nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
};
class FileList final : public nsIDOMFileList,
public nsWrapperCache
{
@ -50,9 +31,6 @@ public:
: mParent(aParent)
{}
static already_AddRefed<FileList>
Create(nsISupports* aParent, FileListClonedData* aData);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -114,9 +92,6 @@ public:
return mFiles.Length();
}
// Useful for cloning
already_AddRefed<FileListClonedData> CreateClonedData() const;
private:
~FileList() {}

View File

@ -28,7 +28,8 @@ PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
nsGlobalWindow* aTargetWindow,
nsIPrincipal* aProvidedPrincipal,
bool aTrustedCaller)
: mSource(aSource),
: StructuredCloneHelper(CloningSupported, TransferringSupported),
mSource(aSource),
mCallerOrigin(aCallerOrigin),
mTargetWindow(aTargetWindow),
mProvidedPrincipal(aProvidedPrincipal),

View File

@ -199,8 +199,10 @@ StructuredCloneHelperInternal::FreeTransferCallback(uint32_t aTag,
// StructuredCloneHelper class
StructuredCloneHelper::StructuredCloneHelper(uint32_t aFlags)
: mFlags(aFlags)
StructuredCloneHelper::StructuredCloneHelper(CloningSupport aSupportsCloning,
TransferringSupport aSupportsTransferring)
: mSupportsCloning(aSupportsCloning == CloningSupported)
, mSupportsTransferring(aSupportsTransferring == TransferringSupported)
, mParent(nullptr)
{}
@ -209,6 +211,13 @@ StructuredCloneHelper::~StructuredCloneHelper()
Shutdown();
}
bool
StructuredCloneHelper::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
return Write(aCx, aValue, JS::UndefinedHandleValue);
}
bool
StructuredCloneHelper::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
@ -227,7 +236,36 @@ StructuredCloneHelper::Read(nsISupports* aParent,
mozilla::AutoRestore<nsISupports*> guard(mParent);
mParent = aParent;
return StructuredCloneHelperInternal::Read(aCx, aValue);
bool ok = StructuredCloneHelperInternal::Read(aCx, aValue);
mBlobImplArray.Clear();
return ok;
}
bool
StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls,
JS::MutableHandle<JS::Value> aValue)
{
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
MOZ_ASSERT(mBlobImplArray.IsEmpty());
MOZ_ASSERT(aBuffer);
MOZ_ASSERT_IF(!mSupportsCloning, aBlobImpls.IsEmpty());
mozilla::AutoRestore<nsISupports*> guard(mParent);
mParent = aParent;
mBlobImplArray.AppendElements(aBlobImpls);
bool ok = JS_ReadStructuredClone(aCx, aBuffer, aBufferLength,
JS_STRUCTURED_CLONE_VERSION, aValue,
&gCallbacks, this);
mBlobImplArray.Clear();
return ok;
}
JSObject*
@ -236,54 +274,59 @@ StructuredCloneHelper::ReadCallback(JSContext* aCx,
uint32_t aTag,
uint32_t aIndex)
{
MOZ_ASSERT(mSupportsCloning);
if (aTag == SCTAG_DOM_BLOB) {
MOZ_ASSERT(!(mFlags & eBlobNotSupported));
MOZ_ASSERT(aIndex < mBlobImplArray.Length());
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[aIndex];
BlobImpl* blobImpl;
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
MOZ_ASSERT(blobImpl);
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
return &val.toObject();
}
return &val.toObject();
}
if (aTag == SCTAG_DOM_FILELIST) {
MOZ_ASSERT(!(mFlags & eFileListNotSupported));
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<FileList> fileList = new FileList(mParent);
FileListClonedData* fileListClonedData;
if (JS_ReadBytes(aReader, &fileListClonedData,
sizeof(fileListClonedData))) {
MOZ_ASSERT(fileListClonedData);
// |aIndex| is the number of BlobImpls to use from |offset|.
uint32_t tag, offset;
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
return nullptr;
}
MOZ_ASSERT(tag == 0);
// nsRefPtr<FileList> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<FileList> fileList =
FileList::Create(mParent, fileListClonedData);
if (!fileList || !ToJSValue(aCx, fileList, &val)) {
for (uint32_t i = 0; i < aIndex; ++i) {
uint32_t index = offset + i;
MOZ_ASSERT(index < mBlobImplArray.Length());
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[index];
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file = File::Create(mParent, blobImpl);
if (!fileList->Append(file)) {
return nullptr;
}
}
return &val.toObject();
if (!ToJSValue(aCx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
}
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aIndex, nullptr);
@ -294,27 +337,43 @@ StructuredCloneHelper::WriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj)
{
if (!mSupportsCloning) {
return false;
}
// See if this is a File/Blob object.
if (!(mFlags & eBlobNotSupported)) {
{
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
BlobImpl* blobImpl = blob->Impl();
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, 0) &&
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl)) &&
StoreISupports(blobImpl);
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
mBlobImplArray.Length())) {
mBlobImplArray.AppendElement(blobImpl);
return true;
}
return false;
}
}
if (!(mFlags & eFileListNotSupported)) {
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
nsRefPtr<FileListClonedData> fileListClonedData =
fileList->CreateClonedData();
MOZ_ASSERT(fileListClonedData);
FileListClonedData* ptr = fileListClonedData.get();
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, 0) &&
JS_WriteBytes(aWriter, &ptr, sizeof(ptr)) &&
StoreISupports(fileListClonedData);
// A FileList is serialized writing the X number of elements and the offset
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
// starting from the offset.
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
fileList->Length()) ||
!JS_WriteUint32Pair(aWriter, 0,
mBlobImplArray.Length())) {
return false;
}
for (uint32_t i = 0; i < fileList->Length(); ++i) {
mBlobImplArray.AppendElement(fileList->Item(i)->Impl());
}
return true;
}
}
@ -329,9 +388,9 @@ StructuredCloneHelper::ReadTransferCallback(JSContext* aCx,
uint64_t aExtraData,
JS::MutableHandleObject aReturnObject)
{
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
MOZ_ASSERT(mSupportsTransferring);
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
// This can be null.
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mParent);
@ -370,7 +429,11 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx,
void** aContent,
uint64_t* aExtraData)
{
if (!(mFlags & eMessagePortNotSupported)) {
if (!mSupportsTransferring) {
return false;
}
{
MessagePortBase* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
if (NS_SUCCEEDED(rv)) {
@ -406,8 +469,9 @@ StructuredCloneHelper::FreeTransferCallback(uint32_t aTag,
void* aContent,
uint64_t aExtraData)
{
MOZ_ASSERT(mSupportsTransferring);
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
MOZ_ASSERT(!aContent);
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);

View File

@ -76,6 +76,18 @@ public:
bool Read(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue);
uint64_t* BufferData() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
return mBuffer->data();
}
size_t BufferSize() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
return mBuffer->nbytes();
}
protected:
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
@ -84,32 +96,36 @@ protected:
#endif
};
class BlobImpl;
class MessagePortBase;
class MessagePortIdentifier;
class StructuredCloneHelper : public StructuredCloneHelperInternal
{
public:
enum StructuredCloneHelperFlags {
eAll = 0,
// Disable the cloning of blobs. If a blob is part of the cloning value,
// an exception will be thrown.
eBlobNotSupported = 1 << 0,
// Disable the cloning of FileLists. If a FileList is part of the cloning
// value, an exception will be thrown.
eFileListNotSupported = 1 << 1,
// MessagePort can just be transfered. Using this flag we do not support
// the transfering.
eMessagePortNotSupported = 1 << 2,
enum CloningSupport
{
CloningSupported,
CloningNotSupported
};
// aFlags is a bitmap of StructuredCloneHelperFlags.
explicit StructuredCloneHelper(uint32_t aFlags = eAll);
enum TransferringSupport
{
TransferringSupported,
TransferringNotSupported
};
// If cloning is supported, this object will clone objects such as Blobs,
// FileList, ImageData, etc.
// If transferring is supported, we will transfer MessagePorts and in the
// future other transferrable objects.
explicit StructuredCloneHelper(CloningSupport aSupportsCloning,
TransferringSupport aSupportsTransferring);
virtual ~StructuredCloneHelper();
bool Write(JSContext* aCx,
JS::Handle<JS::Value> aValue);
bool Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer);
@ -118,9 +134,22 @@ public:
JSContext* aCx,
JS::MutableHandle<JS::Value> aValue);
bool ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
nsTArray<nsRefPtr<BlobImpl>>& aBlobImpls,
JS::MutableHandle<JS::Value> aValue);
const nsTArray<nsRefPtr<BlobImpl>>& ClonedBlobImpls() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
return mBlobImplArray;
}
nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts()
{
MOZ_ASSERT(!(mFlags & eMessagePortNotSupported));
MOZ_ASSERT(mSupportsTransferring);
return mTransferredPorts;
}
@ -154,19 +183,12 @@ public:
void* aContent,
uint64_t aExtraData) override;
private:
bool StoreISupports(nsISupports* aSupports)
{
MOZ_ASSERT(aSupports);
mSupportsArray.AppendElement(aSupports);
return true;
}
// This is our bitmap.
uint32_t mFlags;
bool mSupportsCloning;
bool mSupportsTransferring;
// Useful for the structured clone algorithm:
nsTArray<nsCOMPtr<nsISupports>> mSupportsArray;
nsTArray<nsRefPtr<BlobImpl>> mBlobImplArray;
// This raw pointer is set and unset into the ::Read(). It's always null
// outside that method. For this reason it's a raw pointer.

View File

@ -231,12 +231,51 @@ function test_windowToIframeURL(url) {
document.body.appendChild(ifr);
}
function test_broadcastChannel() {
info("Testing broadcastChannel");
var bc1 = new BroadcastChannel('postMessagesTest');
var bc2 = new BroadcastChannel('postMessagesTest');
var resolve;
bc2.onmessage = function(e) {
if (!resolve) {
ok(false, "Unexpected message!");
return;
}
let tmp = resolve;
resolve = null;
tmp({ data: e.data, ports: [] });
}
runTests({
clonableObjects: true,
transferableObjects: false,
send: function(what, ports) {
is(ports.length, 0, "No ports for this test!");
return new Promise(function(r, rr) {
resolve = r;
bc1.postMessage(what);
});
},
finished: function() {
onmessage = null;
next();
}
});
}
var tests = [
create_fileList,
test_windowToWindow,
test_windowToIframe,
test_windowToCrossOriginIframe,
test_broadcastChannel,
];
function next() {

View File

@ -8,7 +8,8 @@
#include "BroadcastChannelChild.h"
#include "mozilla/dom/BroadcastChannelBinding.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
@ -30,20 +31,18 @@ namespace dom {
using namespace workers;
class BroadcastChannelMessage final
class BroadcastChannelMessage final : public StructuredCloneHelper
{
public:
NS_INLINE_DECL_REFCOUNTING(BroadcastChannelMessage)
JSAutoStructuredCloneBuffer mBuffer;
StructuredCloneClosure mClosure;
BroadcastChannelMessage()
{ }
: StructuredCloneHelper(CloningSupported, TransferringNotSupported)
{}
private:
~BroadcastChannelMessage()
{ }
{}
};
namespace {
@ -166,13 +165,13 @@ public:
ClonedMessageData message;
SerializedStructuredCloneBuffer& buffer = message.data();
buffer.data = mData->mBuffer.data();
buffer.dataLength = mData->mBuffer.nbytes();
buffer.data = mData->BufferData();
buffer.dataLength = mData->BufferSize();
PBackgroundChild* backgroundManager = mActor->Manager();
MOZ_ASSERT(backgroundManager);
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = mData->mClosure.mBlobImpls;
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = mData->ClonedBlobImpls();
if (!blobImpls.IsEmpty()) {
message.blobsChild().SetCapacity(blobImpls.Length());
@ -455,12 +454,12 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
{
nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
if (!WriteStructuredClone(aCx, aMessage, data->mBuffer, data->mClosure)) {
if (!data->Write(aCx, aMessage)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->mClosure.mBlobImpls;
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->ClonedBlobImpls();
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);

View File

@ -11,7 +11,7 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/ScriptSettings.h"
@ -86,15 +86,15 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
}
JSContext* cx = jsapi.cx();
const SerializedStructuredCloneBuffer& buffer = aData.data();
StructuredCloneData cloneData;
cloneData.mData = buffer.data;
cloneData.mDataLength = buffer.dataLength;
cloneData.mClosure.mBlobImpls.SwapElements(blobs);
StructuredCloneHelper cloneHelper(StructuredCloneHelper::CloningSupported,
StructuredCloneHelper::TransferringNotSupported);
JS::Rooted<JS::Value> value(cx, JS::NullValue());
if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) {
if (buffer.dataLength &&
!cloneHelper.ReadFromBuffer(mBC->GetParentObject(), cx,
buffer.data, buffer.dataLength, blobs,
&value)) {
JS_ClearPendingException(cx);
return false;
}

View File

@ -16,6 +16,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/ErrorResult.h"
#include "WorkerPrivate.h"
@ -207,8 +208,8 @@ protected:
// A DataStoreRunnable to run DataStore::Put(...) on the main thread.
class DataStorePutRunnable final : public DataStoreProxyRunnable
, public StructuredCloneHelper
{
JSAutoStructuredCloneBuffer mObjBuffer;
const StringOrUnsignedLong& mId;
const nsString mRevisionId;
ErrorResult& mRv;
@ -223,6 +224,7 @@ public:
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, StructuredCloneHelper(CloningNotSupported, TransferringNotSupported)
, mId(aId)
, mRevisionId(aRevisionId)
, mRv(aRv)
@ -231,7 +233,7 @@ public:
aWorkerPrivate->AssertIsOnWorkerThread();
// This needs to be structured cloned while it's still on the worker thread.
if (!mObjBuffer.write(aCx, aObj)) {
if (!Write(aCx, aObj)) {
JS_ClearPendingException(aCx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
@ -252,7 +254,7 @@ protected:
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> value(cx);
if (!mObjBuffer.read(cx, &value)) {
if (!Read(mBackingStore->GetParentObject(), cx, &value)) {
JS_ClearPendingException(cx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return true;
@ -270,8 +272,8 @@ protected:
// A DataStoreRunnable to run DataStore::Add(...) on the main thread.
class DataStoreAddRunnable final : public DataStoreProxyRunnable
, public StructuredCloneHelper
{
JSAutoStructuredCloneBuffer mObjBuffer;
const Optional<StringOrUnsignedLong>& mId;
const nsString mRevisionId;
ErrorResult& mRv;
@ -286,6 +288,7 @@ public:
const nsAString& aRevisionId,
ErrorResult& aRv)
: DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
, StructuredCloneHelper(CloningNotSupported, TransferringNotSupported)
, mId(aId)
, mRevisionId(aRevisionId)
, mRv(aRv)
@ -294,7 +297,7 @@ public:
aWorkerPrivate->AssertIsOnWorkerThread();
// This needs to be structured cloned while it's still on the worker thread.
if (!mObjBuffer.write(aCx, aObj)) {
if (!Write(aCx, aObj)) {
JS_ClearPendingException(aCx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
@ -315,7 +318,7 @@ protected:
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> value(cx);
if (!mObjBuffer.read(cx, &value)) {
if (!Read(mBackingStore->GetParentObject(), cx, &value)) {
JS_ClearPendingException(cx);
mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return true;