Bug 1264053 - MessagePort should support transferable objects in multi-e10s, r=sfink, r=smaug, r=jorendorff, r=janv

This commit is contained in:
Andrea Marchesini 2016-07-21 15:29:42 +02:00
parent faa4e6f42c
commit a183983968
16 changed files with 166 additions and 83 deletions

View File

@ -36,7 +36,7 @@ PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource,
nsIDocument* aSourceDocument,
bool aTrustedCaller)
: StructuredCloneHolder(CloningSupported, TransferringSupported,
SameProcessSameThread),
StructuredCloneScope::SameProcessSameThread),
mSource(aSource),
mCallerOrigin(aCallerOrigin),
mTargetWindow(aTargetWindow),

View File

@ -146,9 +146,10 @@ const JSStructuredCloneCallbacks gCallbacks = {
// StructuredCloneHolderBase class
StructuredCloneHolderBase::StructuredCloneHolderBase()
StructuredCloneHolderBase::StructuredCloneHolderBase(StructuredCloneScope aScope)
: mStructuredCloneScope(aScope)
#ifdef DEBUG
: mClearCalled(false)
, mClearCalled(false)
#endif
{}
@ -184,7 +185,7 @@ StructuredCloneHolderBase::Write(JSContext* aCx,
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
mBuffer = new JSAutoStructuredCloneBuffer(mStructuredCloneScope, &gCallbacks, this);
if (!mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this)) {
mBuffer = nullptr;
@ -242,10 +243,10 @@ StructuredCloneHolderBase::CustomFreeTransferHandler(uint32_t aTag,
StructuredCloneHolder::StructuredCloneHolder(CloningSupport aSupportsCloning,
TransferringSupport aSupportsTransferring,
ContextSupport aContext)
: mSupportsCloning(aSupportsCloning == CloningSupported)
StructuredCloneScope aScope)
: StructuredCloneHolderBase(aScope)
, mSupportsCloning(aSupportsCloning == CloningSupported)
, mSupportsTransferring(aSupportsTransferring == TransferringSupported)
, mSupportedContext(aContext)
, mParent(nullptr)
#ifdef DEBUG
, mCreationThread(NS_GetCurrentThread())
@ -272,7 +273,7 @@ StructuredCloneHolder::Write(JSContext* aCx,
JS::Handle<JS::Value> aTransfer,
ErrorResult& aRv)
{
MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
mCreationThread == NS_GetCurrentThread());
if (!StructuredCloneHolderBase::Write(aCx, aValue, aTransfer)) {
@ -280,7 +281,7 @@ StructuredCloneHolder::Write(JSContext* aCx,
return;
}
if (mSupportedContext != SameProcessSameThread) {
if (mStructuredCloneScope != StructuredCloneScope::SameProcessSameThread) {
for (uint32_t i = 0, len = mBlobImplArray.Length(); i < len; ++i) {
if (!mBlobImplArray[i]->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
@ -296,7 +297,7 @@ StructuredCloneHolder::Read(nsISupports* aParent,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
{
MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
mCreationThread == NS_GetCurrentThread());
MOZ_ASSERT(aParent);
@ -337,7 +338,7 @@ StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
{
MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
mCreationThread == NS_GetCurrentThread());
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
@ -347,7 +348,8 @@ StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
mParent = aParent;
if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength, aAlgorithmVersion,
aValue, &gCallbacks, this)) {
mStructuredCloneScope, aValue, &gCallbacks,
this)) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
@ -357,7 +359,7 @@ void
StructuredCloneHolder::MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
ErrorResult& aRv)
{
MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread,
mCreationThread == NS_GetCurrentThread());
MOZ_ASSERT(mBuffer, "MoveBuffer() cannot be called without a Write().");
@ -1041,8 +1043,8 @@ WriteFormData(JSStructuredCloneWriter* aWriter,
if (aValue.IsDirectory()) {
Directory* directory = aValue.GetAsDirectory();
if (closure->mHolder->SupportedContext() !=
StructuredCloneHolder::SameProcessSameThread &&
if (closure->mHolder->CloneScope() !=
StructuredCloneHolder::StructuredCloneScope::SameProcessSameThread &&
!directory->ClonableToDifferentThreadOrProcess()) {
return false;
}
@ -1092,8 +1094,8 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
}
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread);
MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
// Get the current global object.
// This can be null.
@ -1127,7 +1129,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
{
Directory* directory = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, aObj, directory))) {
if (mSupportedContext != SameProcessSameThread &&
if (mStructuredCloneScope != StructuredCloneScope::SameProcessSameThread &&
!directory->ClonableToDifferentThreadOrProcess()) {
return false;
}
@ -1153,8 +1155,8 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
}
// See if this is an ImageBitmap object.
if (mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread) {
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
ImageBitmap* imageBitmap = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
return ImageBitmap::WriteStructuredClone(aWriter,
@ -1203,8 +1205,8 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
}
if (aTag == SCTAG_DOM_CANVAS) {
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread);
MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@ -1223,8 +1225,8 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
}
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread);
MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data =
static_cast<ImageBitmapCloneData*>(aContent);
@ -1274,8 +1276,8 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
return true;
}
if (mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread) {
if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) {
OffscreenCanvas* canvas = nullptr;
rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas);
if (NS_SUCCEEDED(rv)) {
@ -1327,8 +1329,8 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
}
if (aTag == SCTAG_DOM_CANVAS) {
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread);
MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aContent);
OffscreenCanvasCloneData* data =
static_cast<OffscreenCanvasCloneData*>(aContent);
@ -1337,8 +1339,8 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
}
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
mSupportedContext == SameProcessDifferentThread);
MOZ_ASSERT(mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread);
MOZ_ASSERT(aContent);
ImageBitmapCloneData* data =
static_cast<ImageBitmapCloneData*>(aContent);

View File

@ -31,7 +31,9 @@ namespace dom {
class StructuredCloneHolderBase
{
public:
StructuredCloneHolderBase();
typedef JS::StructuredCloneScope StructuredCloneScope;
StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
virtual ~StructuredCloneHolderBase();
// These methods should be implemented in order to clone data.
@ -115,6 +117,8 @@ public:
protected:
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
StructuredCloneScope mStructuredCloneScope;
#ifdef DEBUG
bool mClearCalled;
#endif
@ -139,24 +143,17 @@ public:
TransferringNotSupported
};
enum ContextSupport
{
SameProcessSameThread,
SameProcessDifferentThread,
DifferentProcess
};
// 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.
// The ContextSupport is useful to know where the cloned/transferred data can
// be read and written. Additional checks about the nature of the objects
// will be done based on this context value because not all the objects can
// be sent between threads or processes.
// The StructuredCloneScope is useful to know where the cloned/transferred
// data can be read and written. Additional checks about the nature of the
// objects will be done based on this scope value because not all the
// objects can be sent between threads or processes.
explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
TransferringSupport aSupportsTransferring,
ContextSupport aContextSupport);
StructuredCloneScope aStructuredCloneScope);
virtual ~StructuredCloneHolder();
// Normally you should just use Write() and Read().
@ -194,9 +191,9 @@ public:
return mBlobImplArray;
}
ContextSupport SupportedContext() const
StructuredCloneScope CloneScope() const
{
return mSupportedContext;
return mStructuredCloneScope;
}
// The parent object is set internally just during the Read(). This method
@ -294,7 +291,6 @@ protected:
bool mSupportsCloning;
bool mSupportsTransferring;
ContextSupport mSupportedContext;
// Used for cloning blobs in the structured cloning algorithm.
nsTArray<RefPtr<BlobImpl>> mBlobImplArray;

View File

@ -40,7 +40,7 @@ public:
BroadcastChannelMessage()
: StructuredCloneHolder(CloningSupported, TransferringNotSupported,
DifferentProcess)
StructuredCloneScope::DifferentProcess)
{}
private:

View File

@ -149,11 +149,11 @@ class VersionChangeTransaction;
// If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
// schema version.
static_assert(JS_STRUCTURED_CLONE_VERSION == 6,
static_assert(JS_STRUCTURED_CLONE_VERSION == 7,
"Need to update the major schema version.");
// Major schema version. Bump for almost everything.
const uint32_t kMajorSchemaVersion = 23;
const uint32_t kMajorSchemaVersion = 24;
// Minor schema version. Should almost always be 0 (maybe bump on release
// branches if we have to).
@ -4101,6 +4101,19 @@ UpgradeSchemaFrom22_0To23_0(mozIStorageConnection* aConnection,
return NS_OK;
}
nsresult
UpgradeSchemaFrom23_0To24_0(mozIStorageConnection* aConnection)
{
// The only change between 23 and 24 was a different structured clone format,
// but it's backwards-compatible.
nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(24, 0));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
GetDatabaseFileURL(nsIFile* aDatabaseFile,
PersistenceType aPersistenceType,
@ -4607,7 +4620,7 @@ CreateStorageConnection(nsIFile* aDBFile,
}
} else {
// This logic needs to change next time we change the schema!
static_assert(kSQLiteSchemaVersion == int32_t((23 << 4) + 0),
static_assert(kSQLiteSchemaVersion == int32_t((24 << 4) + 0),
"Upgrade function needed due to schema version increase.");
while (schemaVersion != kSQLiteSchemaVersion) {
@ -4651,6 +4664,8 @@ CreateStorageConnection(nsIFile* aDBFile,
rv = UpgradeSchemaFrom21_0To22_0(connection);
} else if (schemaVersion == MakeSchemaVersion(22, 0)) {
rv = UpgradeSchemaFrom22_0To23_0(connection, aOrigin);
} else if (schemaVersion == MakeSchemaVersion(23, 0)) {
rv = UpgradeSchemaFrom23_0To24_0(connection);
} else {
IDB_WARNING("Unable to open IndexedDB database, no upgrade path is "
"available!");

View File

@ -80,7 +80,9 @@ struct IDBObjectStore::StructuredCloneWriteInfo
uint64_t mOffsetToKeyProp;
explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
: mDatabase(aDatabase)
: mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
nullptr)
, mDatabase(aDatabase)
, mOffsetToKeyProp(0)
{
MOZ_ASSERT(aDatabase);
@ -1110,6 +1112,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
// FIXME: Consider to use StructuredCloneHolder here and in other
// deserializing methods.
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
@ -1148,6 +1151,7 @@ IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
};
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
@ -1191,6 +1195,7 @@ IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
};
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}

View File

@ -47,6 +47,8 @@ StructuredCloneFile::operator==(const StructuredCloneFile& aOther) const
inline
StructuredCloneReadInfo::StructuredCloneReadInfo()
: mDatabase(nullptr)
, mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
nullptr)
{
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}
@ -56,6 +58,8 @@ StructuredCloneReadInfo::StructuredCloneReadInfo(
SerializedStructuredCloneReadInfo&& aCloneReadInfo)
: mData(Move(aCloneReadInfo.data()))
, mDatabase(nullptr)
, mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
nullptr)
{
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
}

View File

@ -80,7 +80,7 @@ public:
StructuredCloneData()
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
StructuredCloneHolder::DifferentProcess)
StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
, mExternalData(nullptr)
, mExternalDataLength(0)
{}

View File

@ -24,7 +24,7 @@ public:
SharedMessagePortMessage()
: StructuredCloneHolder(CloningSupported, TransferringSupported,
DifferentProcess)
StructuredCloneScope::DifferentProcess)
{}
void Read(nsISupports* aParent,

View File

@ -93,7 +93,7 @@ class ServiceWorkerClientPostMessageRunnable final
public:
explicit ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId)
: StructuredCloneHolder(CloningSupported, TransferringSupported,
SameProcessDifferentThread)
StructuredCloneScope::SameProcessDifferentThread)
, mWindowId(aWindowId)
{}

View File

@ -674,7 +674,7 @@ public:
TargetAndBusyBehavior aBehavior)
: WorkerRunnable(aWorkerPrivate, aBehavior)
, StructuredCloneHolder(CloningSupported, TransferringSupported,
SameProcessDifferentThread)
StructuredCloneScope::SameProcessDifferentThread)
{
}

View File

@ -244,7 +244,7 @@ public:
const nsAString& aStringBody)
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
, StructuredCloneHolder(CloningSupported, TransferringNotSupported,
SameProcessDifferentThread)
StructuredCloneScope::SameProcessDifferentThread)
, mStringBody(aStringBody)
, mHasUploadListeners(false)
{
@ -502,7 +502,7 @@ public:
JS::Handle<JSObject*> aScopeObj)
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
StructuredCloneHolder(CloningSupported, TransferringNotSupported,
SameProcessDifferentThread),
StructuredCloneScope::SameProcessDifferentThread),
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(aLoaded),
mTotal(aTotal), mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0),
mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(true),
@ -515,7 +515,7 @@ public:
JS::Handle<JSObject*> aScopeObj)
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
StructuredCloneHolder(CloningSupported, TransferringNotSupported,
SameProcessDifferentThread),
StructuredCloneScope::SameProcessDifferentThread),
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),

View File

@ -22,6 +22,13 @@ struct JSStructuredCloneWriter;
// API for the HTML5 internal structured cloning algorithm.
namespace JS {
enum class StructuredCloneScope : uint32_t {
SameProcessSameThread,
SameProcessDifferentThread,
DifferentProcess
};
enum TransferableOwnership {
/** Transferable data has not been filled in yet */
SCTAG_TMO_UNFILLED = 0,
@ -134,7 +141,7 @@ typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwne
// Increment this when anything at all changes in the serialization format.
// (Note that this does not need to be bumped for Transferable-only changes,
// since they are never saved to persistent storage.)
#define JS_STRUCTURED_CLONE_VERSION 6
#define JS_STRUCTURED_CLONE_VERSION 7
struct JSStructuredCloneCallbacks {
ReadStructuredCloneOp read;
@ -148,6 +155,7 @@ struct JSStructuredCloneCallbacks {
/** Note: if the *data contains transferable objects, it can be read only once. */
JS_PUBLIC_API(bool)
JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t version,
JS::StructuredCloneScope scope,
JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
@ -157,6 +165,7 @@ JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t ve
*/
JS_PUBLIC_API(bool)
JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size_t* nbytesp,
JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* optionalCallbacks,
void* closure, JS::HandleValue transferable);
@ -174,6 +183,7 @@ JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
/** RAII sugar for JS_WriteStructuredClone. */
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
const JS::StructuredCloneScope scope_;
uint64_t* data_;
size_t nbytes_;
uint32_t version_;
@ -187,14 +197,9 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
void* closure_;
public:
JSAutoStructuredCloneBuffer()
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
ownTransferables_(NoTransferables),
callbacks_(nullptr), closure_(nullptr)
{}
JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks* callbacks, void* closure)
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* callbacks, void* closure)
: scope_(scope), data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
ownTransferables_(NoTransferables),
callbacks_(callbacks), closure_(closure)
{}

View File

@ -2212,7 +2212,7 @@ Serialize(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSAutoStructuredCloneBuffer clonebuf;
JSAutoStructuredCloneBuffer clonebuf(JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
if (!clonebuf.write(cx, args.get(0), args.get(1)))
return false;
@ -2254,7 +2254,10 @@ Deserialize(JSContext* cx, unsigned argc, Value* vp)
RootedValue deserialized(cx);
if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(),
JS_STRUCTURED_CLONE_VERSION, &deserialized, nullptr, nullptr)) {
JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
&deserialized, nullptr, nullptr))
{
return false;
}
args.rval().set(deserialized);

View File

@ -126,7 +126,7 @@ bool TestCloneObject()
{
JS::RootedObject obj1(cx, CreateNewObject(8, 12));
CHECK(obj1);
JSAutoStructuredCloneBuffer cloned_buffer;
JSAutoStructuredCloneBuffer cloned_buffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
CHECK(cloned_buffer.write(cx, v1, nullptr, nullptr));
JS::RootedValue v2(cx);
@ -164,7 +164,7 @@ bool TestTransferObject()
CHECK(obj);
JS::RootedValue transferable(cx, JS::ObjectValue(*obj));
JSAutoStructuredCloneBuffer cloned_buffer;
JSAutoStructuredCloneBuffer cloned_buffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
CHECK(cloned_buffer.write(cx, v1, transferable, nullptr, nullptr));
JS::RootedValue v2(cx);
CHECK(cloned_buffer.read(cx, &v2, nullptr, nullptr));

View File

@ -71,6 +71,7 @@ using JS::CanonicalizeNaN;
enum StructuredDataType : uint32_t {
/* Structured data types provided by the engine */
SCTAG_FLOAT_MAX = 0xFFF00000,
SCTAG_HEADER = 0xFFF10000,
SCTAG_NULL = 0xFFFF0000,
SCTAG_UNDEFINED,
SCTAG_BOOLEAN,
@ -226,9 +227,10 @@ class SCInput {
struct JSStructuredCloneReader {
public:
explicit JSStructuredCloneReader(SCInput& in, const JSStructuredCloneCallbacks* cb,
explicit JSStructuredCloneReader(SCInput& in, JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* cb,
void* cbClosure)
: in(in), objs(in.context()), allObjs(in.context()),
: in(in), scope(scope), objs(in.context()), allObjs(in.context()),
callbacks(cb), closure(cbClosure) { }
SCInput& input() { return in; }
@ -237,6 +239,7 @@ struct JSStructuredCloneReader {
private:
JSContext* context() { return in.context(); }
bool readHeader();
bool readTransferMap();
template <typename CharT>
@ -254,6 +257,8 @@ struct JSStructuredCloneReader {
SCInput& in;
JS::StructuredCloneScope scope;
// Stack of objects with properties remaining to be read.
AutoValueVector objs;
@ -272,10 +277,11 @@ struct JSStructuredCloneReader {
struct JSStructuredCloneWriter {
public:
explicit JSStructuredCloneWriter(JSContext* cx,
JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* cb,
void* cbClosure,
Value tVal)
: out(cx), objs(out.context()),
: out(cx), scope(scope), objs(out.context()),
counts(out.context()), entries(out.context()),
memory(out.context()), callbacks(cb),
closure(cbClosure), transferable(out.context(), tVal),
@ -289,7 +295,7 @@ struct JSStructuredCloneWriter {
ReportOutOfMemory(context());
return false;
}
return parseTransferable() && writeTransferMap();
return parseTransferable() && writeHeader() && writeTransferMap();
}
bool write(HandleValue v);
@ -306,6 +312,7 @@ struct JSStructuredCloneWriter {
JSContext* context() { return out.context(); }
bool writeHeader();
bool writeTransferMap();
bool writeString(uint32_t tag, JSString* str);
@ -329,6 +336,9 @@ struct JSStructuredCloneWriter {
SCOutput out;
// The (address space, thread) scope within which this clone is valid.
JS::StructuredCloneScope scope;
// Vector of objects with properties remaining to be written.
//
// NB: These can span multiple compartments, so the compartment must be
@ -411,19 +421,21 @@ ReportDataCloneError(JSContext* cx,
bool
WriteStructuredClone(JSContext* cx, HandleValue v, uint64_t** bufp, size_t* nbytesp,
JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* cb, void* cbClosure,
Value transferable)
{
JSStructuredCloneWriter w(cx, cb, cbClosure, transferable);
JSStructuredCloneWriter w(cx, scope, cb, cbClosure, transferable);
return w.init() && w.write(v) && w.extractBuffer(bufp, nbytesp);
}
bool
ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, MutableHandleValue vp,
ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes,
JS::StructuredCloneScope scope, MutableHandleValue vp,
const JSStructuredCloneCallbacks* cb, void* cbClosure)
{
SCInput in(cx, data, nbytes);
JSStructuredCloneReader r(in, cb, cbClosure);
JSStructuredCloneReader r(in, scope, cb, cbClosure);
return r.read(vp);
}
@ -1263,6 +1275,12 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
return reportDataCloneError(JS_SCERR_UNSUPPORTED_TYPE);
}
bool
JSStructuredCloneWriter::writeHeader()
{
return out.writePair(SCTAG_HEADER, (uint32_t)scope);
}
bool
JSStructuredCloneWriter::writeTransferMap()
{
@ -1307,6 +1325,8 @@ JSStructuredCloneWriter::transferOwnership()
// grabbing out pointers from the transferables and stuffing them into the
// transfer map.
uint64_t* point = out.rawBuffer();
MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_HEADER);
point++;
MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
point++;
MOZ_ASSERT(LittleEndian::readUint64(point) == transferableObjects.count());
@ -1342,6 +1362,8 @@ JSStructuredCloneWriter::transferOwnership()
// and malloc'd buffers, not asm.js-ified buffers.
bool hasStealableContents = arrayBuffer->hasStealableContents() &&
(arrayBuffer->isMapped() || arrayBuffer->hasMallocedContents());
if (scope == JS::StructuredCloneScope::DifferentProcess)
hasStealableContents = false;
ArrayBufferObject::BufferContents bufContents =
ArrayBufferObject::stealContents(context(), arrayBuffer, hasStealableContents);
@ -1896,6 +1918,29 @@ JSStructuredCloneReader::startRead(MutableHandleValue vp)
return true;
}
bool
JSStructuredCloneReader::readHeader()
{
uint32_t tag, data;
if (!in.getPair(&tag, &data))
return in.reportTruncated();
if (tag != SCTAG_HEADER) {
// Old structured clone buffer. We must have read it from disk or
// somewhere, so we can assume it's scope-compatible.
return true;
}
MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
if (data < uint32_t(scope)) {
JS_ReportErrorNumber(context(), GetErrorMessage, nullptr,
JSMSG_SC_BAD_SERIALIZED_DATA, "incompatible structured clone scope");
return false;
}
return true;
}
bool
JSStructuredCloneReader::readTransferMap()
{
@ -2071,6 +2116,9 @@ JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag)
bool
JSStructuredCloneReader::read(MutableHandleValue vp)
{
if (!readHeader())
return false;
if (!readTransferMap())
return false;
@ -2178,7 +2226,8 @@ using namespace js;
JS_PUBLIC_API(bool)
JS_ReadStructuredClone(JSContext* cx, uint64_t* buf, size_t nbytes,
uint32_t version, MutableHandleValue vp,
uint32_t version, JS::StructuredCloneScope scope,
MutableHandleValue vp,
const JSStructuredCloneCallbacks* optionalCallbacks,
void* closure)
{
@ -2190,11 +2239,12 @@ JS_ReadStructuredClone(JSContext* cx, uint64_t* buf, size_t nbytes,
return false;
}
const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
return ReadStructuredClone(cx, buf, nbytes, scope, vp, callbacks, closure);
}
JS_PUBLIC_API(bool)
JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_t* nbytesp,
JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* optionalCallbacks,
void* closure, HandleValue transferable)
{
@ -2203,7 +2253,7 @@ JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_
assertSameCompartment(cx, value);
const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
return WriteStructuredClone(cx, value, bufp, nbytesp, callbacks, closure, transferable);
return WriteStructuredClone(cx, value, bufp, nbytesp, scope, callbacks, closure, transferable);
}
JS_PUBLIC_API(bool)
@ -2247,7 +2297,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
JSAutoStructuredCloneBuffer buf;
JSAutoStructuredCloneBuffer buf(JS::StructuredCloneScope::SameProcessSameThread, callbacks, closure);
{
// If we use Maybe<AutoCompartment> here, G++ can't tell that the
// destructor is only called when Maybe::construct was called, and
@ -2266,6 +2316,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
}
JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
: scope_(other.scope_)
{
ownTransferables_ = other.ownTransferables_;
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
@ -2275,6 +2326,7 @@ JSAutoStructuredCloneBuffer&
JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
{
MOZ_ASSERT(&other != this);
MOZ_ASSERT(scope_ == other.scope_);
clear();
ownTransferables_ = other.ownTransferables_;
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
@ -2369,7 +2421,7 @@ JSAutoStructuredCloneBuffer::read(JSContext* cx, MutableHandleValue vp,
{
MOZ_ASSERT(cx);
MOZ_ASSERT(data_);
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, scope_, vp,
optionalCallbacks, closure);
}
@ -2390,6 +2442,7 @@ JSAutoStructuredCloneBuffer::write(JSContext* cx, HandleValue value,
{
clear();
bool ok = JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
scope_,
optionalCallbacks, closure,
transferable);