зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 6 changesets (bug 1264642) for marionette failures a=backout CLOSED TREE
Backed out changeset f0067001c059 (bug 1264642) Backed out changeset 078e5c447f21 (bug 1264642) Backed out changeset 7c60fc4144fb (bug 1264642) Backed out changeset 9f434697ef2e (bug 1264642) Backed out changeset 06fc278fcedf (bug 1264642) Backed out changeset 162098402acc (bug 1264642)
This commit is contained in:
Родитель
6b3d348f17
Коммит
37a02d441d
|
@ -133,9 +133,7 @@ StructuredCloneCallbacksError(JSContext* aCx,
|
|||
NS_WARNING("Failed to clone data.");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
|
||||
const JSStructuredCloneCallbacks gCallbacks = {
|
||||
StructuredCloneCallbacksRead,
|
||||
StructuredCloneCallbacksWrite,
|
||||
StructuredCloneCallbacksError,
|
||||
|
@ -144,6 +142,8 @@ const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
|
|||
StructuredCloneCallbacksFreeTransfer
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// StructuredCloneHolderBase class
|
||||
|
||||
StructuredCloneHolderBase::StructuredCloneHolderBase()
|
||||
|
@ -184,9 +184,9 @@ StructuredCloneHolderBase::Write(JSContext* aCx,
|
|||
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
|
||||
MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
|
||||
|
||||
mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(&StructuredCloneHolder::sCallbacks, this);
|
||||
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
|
||||
|
||||
if (!mBuffer->write(aCx, aValue, aTransfer, &StructuredCloneHolder::sCallbacks, this)) {
|
||||
if (!mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this)) {
|
||||
mBuffer = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ StructuredCloneHolderBase::Read(JSContext* aCx,
|
|||
MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
|
||||
MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
|
||||
|
||||
bool ok = mBuffer->read(aCx, aValue, &StructuredCloneHolder::sCallbacks, this);
|
||||
bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -319,18 +319,20 @@ StructuredCloneHolder::Read(nsISupports* aParent,
|
|||
void
|
||||
StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JSStructuredCloneData& aBuffer,
|
||||
uint64_t* aBuffer,
|
||||
size_t aBufferLength,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
ReadFromBuffer(aParent, aCx, aBuffer,
|
||||
ReadFromBuffer(aParent, aCx, aBuffer, aBufferLength,
|
||||
JS_STRUCTURED_CLONE_VERSION, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JSStructuredCloneData& aBuffer,
|
||||
uint64_t* aBuffer,
|
||||
size_t aBufferLength,
|
||||
uint32_t aAlgorithmVersion,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult& aRv)
|
||||
|
@ -339,17 +341,52 @@ StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
|
|||
mCreationThread == NS_GetCurrentThread());
|
||||
|
||||
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
|
||||
MOZ_ASSERT(aBuffer);
|
||||
|
||||
mozilla::AutoRestore<nsISupports*> guard(mParent);
|
||||
mParent = aParent;
|
||||
|
||||
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion,
|
||||
aValue, &sCallbacks, this)) {
|
||||
if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength, aAlgorithmVersion,
|
||||
aValue, &gCallbacks, this)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneHolder::MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT_IF(mSupportedContext == SameProcessSameThread,
|
||||
mCreationThread == NS_GetCurrentThread());
|
||||
|
||||
MOZ_ASSERT(mBuffer, "MoveBuffer() cannot be called without a Write().");
|
||||
|
||||
if (NS_WARN_IF(!aArray.SetLength(BufferSize(), mozilla::fallible))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t* buffer;
|
||||
size_t size;
|
||||
mBuffer->steal(&buffer, &size);
|
||||
mBuffer = nullptr;
|
||||
|
||||
memcpy(aArray.Elements(), buffer, size);
|
||||
js_free(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneHolder::FreeBuffer(uint64_t* aBuffer,
|
||||
size_t aBufferLength)
|
||||
{
|
||||
MOZ_ASSERT(!mBuffer, "FreeBuffer() must be called without a Write().");
|
||||
MOZ_ASSERT(aBuffer);
|
||||
MOZ_ASSERT(aBufferLength);
|
||||
|
||||
JS_ClearStructuredClone(aBuffer, aBufferLength, &gCallbacks, this, false);
|
||||
}
|
||||
|
||||
/* static */ JSObject*
|
||||
StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
@ -34,8 +34,6 @@ public:
|
|||
StructuredCloneHolderBase();
|
||||
virtual ~StructuredCloneHolderBase();
|
||||
|
||||
StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = default;
|
||||
|
||||
// These methods should be implemented in order to clone data.
|
||||
// Read more documentation in js/public/StructuredClone.h.
|
||||
|
||||
|
@ -102,14 +100,20 @@ public:
|
|||
return !!mBuffer;
|
||||
}
|
||||
|
||||
JSStructuredCloneData& BufferData() const
|
||||
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:
|
||||
UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
|
||||
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mClearCalled;
|
||||
|
@ -155,8 +159,6 @@ public:
|
|||
ContextSupport aContextSupport);
|
||||
virtual ~StructuredCloneHolder();
|
||||
|
||||
StructuredCloneHolder(StructuredCloneHolder&& aOther) = default;
|
||||
|
||||
// Normally you should just use Write() and Read().
|
||||
|
||||
void Write(JSContext* aCx,
|
||||
|
@ -173,6 +175,12 @@ public:
|
|||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult &aRv);
|
||||
|
||||
// Sometimes, when IPC is involved, you must send a buffer after a Write().
|
||||
// This method 'steals' the internal data from this class.
|
||||
// You should free this buffer with StructuredCloneHolder::FreeBuffer().
|
||||
void MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Call this method to know if this object is keeping some DOM object alive.
|
||||
bool HasClonedDOMObjects() const
|
||||
{
|
||||
|
@ -261,25 +269,29 @@ public:
|
|||
JSStructuredCloneWriter* aWriter,
|
||||
JS::Handle<JSObject*> aObj);
|
||||
|
||||
static const JSStructuredCloneCallbacks sCallbacks;
|
||||
|
||||
protected:
|
||||
// If you receive a buffer from IPC, you can use this method to retrieve a
|
||||
// JS::Value. It can happen that you want to pre-populate the array of Blobs
|
||||
// and/or the PortIdentifiers.
|
||||
void ReadFromBuffer(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JSStructuredCloneData& aBuffer,
|
||||
uint64_t* aBuffer,
|
||||
size_t aBufferLength,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult &aRv);
|
||||
|
||||
void ReadFromBuffer(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JSStructuredCloneData& aBuffer,
|
||||
uint64_t* aBuffer,
|
||||
size_t aBufferLength,
|
||||
uint32_t aAlgorithmVersion,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult &aRv);
|
||||
|
||||
// Use this method to free a buffer generated by MoveToBuffer().
|
||||
void FreeBuffer(uint64_t* aBuffer,
|
||||
size_t aBufferLength);
|
||||
|
||||
bool mSupportsCloning;
|
||||
bool mSupportsTransferring;
|
||||
ContextSupport mSupportedContext;
|
||||
|
|
|
@ -276,13 +276,8 @@ BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType*
|
|||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
auto iter = aData.Data().Iter();
|
||||
size_t size = aData.Data().Size();
|
||||
bool success;
|
||||
buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
return false;
|
||||
}
|
||||
buffer.data = aData.Data();
|
||||
buffer.dataLength = aData.DataLength();
|
||||
aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
|
||||
|
@ -330,7 +325,7 @@ UnpackClonedMessageData(const ClonedMessageData& aClonedData,
|
|||
const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
|
||||
const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
|
||||
|
||||
aData.UseExternalData(buffer.data);
|
||||
aData.UseExternalData(buffer.data, buffer.dataLength);
|
||||
|
||||
aData.PortIdentifiers().AppendElements(identifiers);
|
||||
|
||||
|
|
|
@ -137,11 +137,7 @@ nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto iter = Data().Iter();
|
||||
size_t size = Data().Size();
|
||||
nsAutoCString binaryData;
|
||||
binaryData.SetLength(size);
|
||||
Data().ReadBytes(iter, binaryData.BeginWriting(), size);
|
||||
nsAutoCString binaryData(reinterpret_cast<char*>(Data()), DataLength());
|
||||
nsAutoCString base64Data;
|
||||
nsresult rv = Base64Encode(binaryData, base64Data);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -152,13 +152,9 @@ public:
|
|||
|
||||
ClonedMessageData message;
|
||||
|
||||
bool success;
|
||||
SerializedStructuredCloneBuffer& buffer = message.data();
|
||||
auto iter = mData->BufferData().Iter();
|
||||
buffer.data = mData->BufferData().Borrow<js::SystemAllocPolicy>(iter, mData->BufferData().Size(), &success);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
return NS_OK;
|
||||
}
|
||||
buffer.data = mData->BufferData();
|
||||
buffer.dataLength = mData->BufferSize();
|
||||
|
||||
PBackgroundChild* backgroundManager = mActor->Manager();
|
||||
MOZ_ASSERT(backgroundManager);
|
||||
|
|
|
@ -91,11 +91,12 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData)
|
|||
cloneData.BlobImpls().AppendElements(blobs);
|
||||
|
||||
const SerializedStructuredCloneBuffer& buffer = aData.data();
|
||||
cloneData.UseExternalData(buffer.data, buffer.dataLength);
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> value(cx, JS::NullValue());
|
||||
if (buffer.data.Size()) {
|
||||
if (buffer.dataLength) {
|
||||
ErrorResult rv;
|
||||
cloneData.UseExternalData(buffer.data);
|
||||
cloneData.Read(cx, &value, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
|
|
|
@ -430,6 +430,8 @@ private:
|
|||
{
|
||||
bool ok = IDBObjectStore::DeserializeValue(aCx, *aCloneInfo, aResult);
|
||||
|
||||
aCloneInfo->mCloneBuffer.clear();
|
||||
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
|
|
@ -14819,7 +14819,7 @@ TransactionBase::VerifyRequestParams(const ObjectStoreAddPutParams& aParams)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aParams.cloneInfo().data().data.Size())) {
|
||||
if (NS_WARN_IF(aParams.cloneInfo().data().IsEmpty())) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
@ -14834,13 +14834,13 @@ TransactionBase::VerifyRequestParams(const ObjectStoreAddPutParams& aParams)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(cloneInfo.data().data.Size() < sizeof(uint64_t))) {
|
||||
if (NS_WARN_IF(cloneInfo.data().Length() < sizeof(uint64_t))) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(cloneInfo.offsetToKeyProp() >
|
||||
(cloneInfo.data().data.Size() - sizeof(uint64_t)))) {
|
||||
(cloneInfo.data().Length() - sizeof(uint64_t)))) {
|
||||
ASSERT_UNLESS_FUZZING();
|
||||
return false;
|
||||
}
|
||||
|
@ -19044,9 +19044,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
|
|||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
if (!aInfo->mData.WriteBytes(uncompressedBuffer, uncompressed.Length())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aInfo->mData.SwapElements(uncompressed);
|
||||
|
||||
if (!aFileIds.IsVoid()) {
|
||||
AutoTArray<int64_t, 10> array;
|
||||
|
@ -25408,15 +25406,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
MOZ_ASSERT(!keyUnset || mMetadata->mCommonMetadata.autoIncrement(),
|
||||
"Should have key unless autoIncrement");
|
||||
|
||||
JSStructuredCloneData& data =
|
||||
const_cast<JSStructuredCloneData&>(mParams.cloneInfo().data().data);
|
||||
const char* cloneData;
|
||||
size_t cloneDataSize = data.Size();
|
||||
auto iter = data.Iter();
|
||||
if (NS_WARN_IF(!data.FlattenBytes(iter, &cloneData, cloneDataSize))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int64_t autoIncrementNum = 0;
|
||||
|
||||
if (mMetadata->mCommonMetadata.autoIncrement()) {
|
||||
|
@ -25438,14 +25427,16 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
if (keyUnset && keyPath.IsValid()) {
|
||||
const SerializedStructuredCloneWriteInfo& cloneInfo = mParams.cloneInfo();
|
||||
MOZ_ASSERT(cloneInfo.offsetToKeyProp());
|
||||
MOZ_ASSERT(cloneDataSize > sizeof(uint64_t));
|
||||
MOZ_ASSERT(cloneInfo.data().Length() > sizeof(uint64_t));
|
||||
MOZ_ASSERT(cloneInfo.offsetToKeyProp() <=
|
||||
(cloneDataSize - sizeof(uint64_t)));
|
||||
(cloneInfo.data().Length() - sizeof(uint64_t)));
|
||||
|
||||
// Special case where someone put an object into an autoIncrement'ing
|
||||
// objectStore with no key in its keyPath set. We needed to figure out
|
||||
// which row id we would get above before we could set that properly.
|
||||
char* keyPropPointer = const_cast<char*>(cloneData + cloneInfo.offsetToKeyProp());
|
||||
uint8_t* keyPropPointer =
|
||||
const_cast<uint8_t*>(cloneInfo.data().Elements() +
|
||||
cloneInfo.offsetToKeyProp());
|
||||
uint64_t keyPropValue =
|
||||
ReinterpretDoubleAsUInt64(static_cast<double>(autoIncrementNum));
|
||||
|
||||
|
@ -25456,8 +25447,9 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
key.BindToStatement(stmt, NS_LITERAL_CSTRING("key"));
|
||||
|
||||
// Compress the bytes before adding into the database.
|
||||
const char* uncompressed = cloneData;
|
||||
size_t uncompressedLength = cloneDataSize;
|
||||
const char* uncompressed =
|
||||
reinterpret_cast<const char*>(mParams.cloneInfo().data().Elements());
|
||||
size_t uncompressedLength = mParams.cloneInfo().data().Length();
|
||||
|
||||
// We don't have a smart pointer class that calls free, so we need to
|
||||
// manage | compressed | manually.
|
||||
|
@ -25789,7 +25781,7 @@ ObjectStoreGetRequestOp::ConvertResponse(
|
|||
|
||||
StructuredCloneReadInfo& info = mResponse[aIndex];
|
||||
|
||||
aSerializedInfo.data().data = Move(info.mData);
|
||||
info.mData.SwapElements(aSerializedInfo.data());
|
||||
|
||||
FallibleTArray<BlobOrMutableFile> blobs;
|
||||
nsresult rv = ConvertBlobsToActors(mBackgroundParent,
|
||||
|
@ -26512,7 +26504,7 @@ IndexGetRequestOp::GetResponse(RequestResponse& aResponse)
|
|||
SerializedStructuredCloneReadInfo& serializedInfo =
|
||||
fallibleCloneInfos[index];
|
||||
|
||||
serializedInfo.data().data = Move(info.mData);
|
||||
info.mData.SwapElements(serializedInfo.data());
|
||||
|
||||
FallibleTArray<BlobOrMutableFile> blobs;
|
||||
nsresult rv = ConvertBlobsToActors(mBackgroundParent,
|
||||
|
@ -26546,7 +26538,7 @@ IndexGetRequestOp::GetResponse(RequestResponse& aResponse)
|
|||
SerializedStructuredCloneReadInfo& serializedInfo =
|
||||
aResponse.get_IndexGetResponse().cloneInfo();
|
||||
|
||||
serializedInfo.data().data = Move(info.mData);
|
||||
info.mData.SwapElements(serializedInfo.data());
|
||||
|
||||
FallibleTArray<BlobOrMutableFile> blobs;
|
||||
nsresult rv =
|
||||
|
@ -26860,7 +26852,7 @@ CursorOpBase::PopulateResponseFromStatement(
|
|||
|
||||
auto& responses = mResponse.get_ArrayOfObjectStoreCursorResponse();
|
||||
auto& response = *responses.AppendElement();
|
||||
response.cloneInfo().data().data = Move(cloneInfo.mData);
|
||||
response.cloneInfo().data().SwapElements(cloneInfo.mData);
|
||||
response.key() = mCursor->mKey;
|
||||
|
||||
mFiles.AppendElement(Move(cloneInfo.mFiles));
|
||||
|
@ -26898,7 +26890,7 @@ CursorOpBase::PopulateResponseFromStatement(
|
|||
mResponse = IndexCursorResponse();
|
||||
|
||||
auto& response = mResponse.get_IndexCursorResponse();
|
||||
response.cloneInfo().data().data = Move(cloneInfo.mData);
|
||||
response.cloneInfo().data().SwapElements(cloneInfo.mData);
|
||||
response.key() = mCursor->mKey;
|
||||
response.sortKey() = mCursor->mSortKey;
|
||||
response.objectKey() = mCursor->mObjectKey;
|
||||
|
|
|
@ -105,6 +105,36 @@ struct IDBObjectStore::StructuredCloneWriteInfo
|
|||
{
|
||||
MOZ_COUNT_DTOR(StructuredCloneWriteInfo);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const StructuredCloneWriteInfo& aOther) const
|
||||
{
|
||||
return this->mCloneBuffer.nbytes() == aOther.mCloneBuffer.nbytes() &&
|
||||
this->mCloneBuffer.data() == aOther.mCloneBuffer.data() &&
|
||||
this->mBlobOrMutableFiles == aOther.mBlobOrMutableFiles &&
|
||||
this->mDatabase == aOther.mDatabase &&
|
||||
this->mOffsetToKeyProp == aOther.mOffsetToKeyProp;
|
||||
}
|
||||
|
||||
bool
|
||||
SetFromSerialized(const SerializedStructuredCloneWriteInfo& aOther)
|
||||
{
|
||||
if (aOther.data().IsEmpty()) {
|
||||
mCloneBuffer.clear();
|
||||
} else {
|
||||
auto* aOtherBuffer =
|
||||
reinterpret_cast<uint64_t*>(
|
||||
const_cast<uint8_t*>(aOther.data().Elements()));
|
||||
if (!mCloneBuffer.copy(aOtherBuffer, aOther.data().Length())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mBlobOrMutableFiles.Clear();
|
||||
|
||||
mOffsetToKeyProp = aOther.offsetToKeyProp();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
@ -865,6 +895,15 @@ CommonStructuredCloneReadCallback(JSContext* aCx,
|
|||
aTag);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
|
||||
{
|
||||
if (aBuffer.data()) {
|
||||
aBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const JSClass IDBObjectStore::sDummyPropJSClass = {
|
||||
|
@ -1031,10 +1070,11 @@ IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
|
|||
// This is kind of tricky, we only want to release stuff on the main thread,
|
||||
// but we can end up being called on other threads if we have already been
|
||||
// cleared on the main thread.
|
||||
if (!aReadInfo.mFiles.Length()) {
|
||||
if (!aReadInfo.mCloneBuffer.data() && !aReadInfo.mFiles.Length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer);
|
||||
aReadInfo.mFiles.Clear();
|
||||
}
|
||||
|
||||
|
@ -1046,12 +1086,15 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
|
|||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
if (!aCloneReadInfo.mData.Size()) {
|
||||
if (aCloneReadInfo.mData.IsEmpty()) {
|
||||
aValue.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
||||
auto* data = reinterpret_cast<uint64_t*>(aCloneReadInfo.mData.Elements());
|
||||
size_t dataLen = aCloneReadInfo.mData.Length();
|
||||
|
||||
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
|
@ -1066,7 +1109,7 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
|
|||
|
||||
// FIXME: Consider to use StructuredCloneHolder here and in other
|
||||
// deserializing methods.
|
||||
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
|
||||
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
|
||||
aValue, &callbacks, &aCloneReadInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1083,12 +1126,18 @@ IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
|
|||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
if (!aCloneReadInfo.mData.Size()) {
|
||||
if (aCloneReadInfo.mData.IsEmpty()) {
|
||||
aValue.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
||||
size_t dataLen = aCloneReadInfo.mData.Length();
|
||||
|
||||
uint64_t* data =
|
||||
const_cast<uint64_t*>(reinterpret_cast<uint64_t*>(
|
||||
aCloneReadInfo.mData.Elements()));
|
||||
|
||||
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
|
@ -1098,7 +1147,7 @@ IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
|
|||
nullptr
|
||||
};
|
||||
|
||||
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
|
||||
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
|
||||
aValue, &callbacks, &aCloneReadInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1117,12 +1166,18 @@ IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
|
|||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
if (!aCloneReadInfo.mData.Size()) {
|
||||
if (aCloneReadInfo.mData.IsEmpty()) {
|
||||
aValue.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
||||
size_t dataLen = aCloneReadInfo.mData.Length();
|
||||
|
||||
uint64_t* data =
|
||||
const_cast<uint64_t*>(reinterpret_cast<uint64_t*>(
|
||||
aCloneReadInfo.mData.Elements()));
|
||||
|
||||
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
|
@ -1135,7 +1190,7 @@ IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
|
|||
nullptr
|
||||
};
|
||||
|
||||
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
|
||||
if (!JS_ReadStructuredClone(aCx, data, dataLen, JS_STRUCTURED_CLONE_VERSION,
|
||||
aValue, &callbacks, &aCloneReadInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1266,9 +1321,22 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> cloneData;
|
||||
if (NS_WARN_IF(!cloneData.SetLength(cloneWriteInfo.mCloneBuffer.nbytes(),
|
||||
fallible))) {
|
||||
aRv = NS_ERROR_OUT_OF_MEMORY;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// XXX Remove this
|
||||
memcpy(cloneData.Elements(), cloneWriteInfo.mCloneBuffer.data(),
|
||||
cloneWriteInfo.mCloneBuffer.nbytes());
|
||||
|
||||
cloneWriteInfo.mCloneBuffer.clear();
|
||||
|
||||
ObjectStoreAddPutParams commonParams;
|
||||
commonParams.objectStoreId() = Id();
|
||||
commonParams.cloneInfo().data().data = Move(cloneWriteInfo.mCloneBuffer.data());
|
||||
commonParams.cloneInfo().data().SwapElements(cloneData);
|
||||
commonParams.cloneInfo().offsetToKeyProp() = cloneWriteInfo.mOffsetToKeyProp;
|
||||
commonParams.key() = key;
|
||||
commonParams.indexUpdateInfos().SwapElements(updateInfo);
|
||||
|
|
|
@ -45,10 +45,13 @@ struct StructuredCloneFile
|
|||
|
||||
struct StructuredCloneReadInfo
|
||||
{
|
||||
JSStructuredCloneData mData;
|
||||
nsTArray<uint8_t> mData;
|
||||
nsTArray<StructuredCloneFile> mFiles;
|
||||
IDBDatabase* mDatabase;
|
||||
|
||||
// XXX Remove!
|
||||
JSAutoStructuredCloneBuffer mCloneBuffer;
|
||||
|
||||
// In IndexedDatabaseInlines.h
|
||||
inline
|
||||
StructuredCloneReadInfo();
|
||||
|
@ -57,10 +60,6 @@ struct StructuredCloneReadInfo
|
|||
inline
|
||||
~StructuredCloneReadInfo();
|
||||
|
||||
// In IndexedDatabaseInlines.h
|
||||
inline
|
||||
StructuredCloneReadInfo(StructuredCloneReadInfo&& aOther);
|
||||
|
||||
// In IndexedDatabaseInlines.h
|
||||
inline StructuredCloneReadInfo&
|
||||
operator=(StructuredCloneReadInfo&& aOther);
|
||||
|
|
|
@ -51,24 +51,10 @@ StructuredCloneReadInfo::StructuredCloneReadInfo()
|
|||
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
|
||||
}
|
||||
|
||||
inline
|
||||
StructuredCloneReadInfo::StructuredCloneReadInfo(
|
||||
StructuredCloneReadInfo&& aCloneReadInfo)
|
||||
: mData(Move(aCloneReadInfo.mData))
|
||||
{
|
||||
MOZ_ASSERT(&aCloneReadInfo != this);
|
||||
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
|
||||
|
||||
mFiles.Clear();
|
||||
mFiles.SwapElements(aCloneReadInfo.mFiles);
|
||||
mDatabase = aCloneReadInfo.mDatabase;
|
||||
aCloneReadInfo.mDatabase = nullptr;
|
||||
}
|
||||
|
||||
inline
|
||||
StructuredCloneReadInfo::StructuredCloneReadInfo(
|
||||
SerializedStructuredCloneReadInfo&& aCloneReadInfo)
|
||||
: mData(Move(aCloneReadInfo.data().data))
|
||||
: mData(Move(aCloneReadInfo.data()))
|
||||
, mDatabase(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(StructuredCloneReadInfo);
|
||||
|
@ -86,6 +72,7 @@ StructuredCloneReadInfo::operator=(StructuredCloneReadInfo&& aCloneReadInfo)
|
|||
MOZ_ASSERT(&aCloneReadInfo != this);
|
||||
|
||||
mData = Move(aCloneReadInfo.mData);
|
||||
mCloneBuffer = Move(aCloneReadInfo.mCloneBuffer);
|
||||
mFiles.Clear();
|
||||
mFiles.SwapElements(aCloneReadInfo.mFiles);
|
||||
mDatabase = aCloneReadInfo.mDatabase;
|
||||
|
|
|
@ -30,9 +30,6 @@ using class mozilla::dom::indexedDB::KeyPath
|
|||
using mozilla::dom::quota::PersistenceType
|
||||
from "mozilla/dom/quota/PersistenceType.h";
|
||||
|
||||
using mozilla::SerializedStructuredCloneBuffer
|
||||
from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
@ -60,13 +57,13 @@ union BlobOrMutableFile
|
|||
|
||||
struct SerializedStructuredCloneReadInfo
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
uint8_t[] data;
|
||||
BlobOrMutableFile[] blobs;
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneWriteInfo
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
uint8_t[] data;
|
||||
uint64_t offsetToKeyProp;
|
||||
};
|
||||
|
||||
|
|
|
@ -65,8 +65,7 @@ using mozilla::WritingMode from "mozilla/WritingModes.h";
|
|||
using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
|
||||
using nsIWidget::TouchPointerState from "nsIWidget.h";
|
||||
using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
|
||||
using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::EventMessage from "mozilla/EventForwards.h";
|
||||
using nsEventStatus from "mozilla/EventForwards.h";
|
||||
using nsSizeMode from "nsIWidgetListener.h";
|
||||
|
|
|
@ -95,8 +95,7 @@ using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
|
|||
using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
|
||||
using mozilla::LayoutDeviceIntPoint from "Units.h";
|
||||
using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
|
||||
using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
|
||||
using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
|
||||
|
|
|
@ -16,8 +16,7 @@ include PTabContext;
|
|||
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
||||
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
|
||||
using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
|
||||
using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace ipc {
|
|||
bool
|
||||
StructuredCloneData::Copy(const StructuredCloneData& aData)
|
||||
{
|
||||
if (!aData.mInitialized) {
|
||||
if (!aData.Data()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,8 @@ StructuredCloneData::Copy(const StructuredCloneData& aData)
|
|||
mSharedData = aData.SharedData();
|
||||
} else {
|
||||
mSharedData =
|
||||
SharedJSAllocatedData::CreateFromExternalData(aData.Data());
|
||||
SharedJSAllocatedData::CreateFromExternalData(aData.Data(),
|
||||
aData.DataLength());
|
||||
NS_ENSURE_TRUE(mSharedData, false);
|
||||
}
|
||||
|
||||
|
@ -47,8 +48,6 @@ StructuredCloneData::Copy(const StructuredCloneData& aData)
|
|||
|
||||
MOZ_ASSERT(GetSurfaces().IsEmpty());
|
||||
|
||||
mInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,12 +56,12 @@ StructuredCloneData::Read(JSContext* aCx,
|
|||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult &aRv)
|
||||
{
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(Data());
|
||||
|
||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
ReadFromBuffer(global, aCx, Data(), aValue, aRv);
|
||||
ReadFromBuffer(global, aCx, Data(), DataLength(), aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -79,50 +78,64 @@ StructuredCloneData::Write(JSContext* aCx,
|
|||
JS::Handle<JS::Value> aTransfer,
|
||||
ErrorResult &aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
MOZ_ASSERT(!Data());
|
||||
|
||||
StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSStructuredCloneData data;
|
||||
mBuffer->abandon();
|
||||
mBuffer->steal(&data);
|
||||
uint64_t* data = nullptr;
|
||||
size_t dataLength = 0;
|
||||
mBuffer->steal(&data, &dataLength);
|
||||
mBuffer = nullptr;
|
||||
mSharedData = new SharedJSAllocatedData(Move(data));
|
||||
mInitialized = true;
|
||||
mSharedData = new SharedJSAllocatedData(data, dataLength);
|
||||
}
|
||||
|
||||
void
|
||||
StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
|
||||
{
|
||||
WriteParam(aMsg, Data());
|
||||
WriteParam(aMsg, DataLength());
|
||||
|
||||
if (DataLength()) {
|
||||
aMsg->WriteBytes(Data(), DataLength());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
|
||||
PickleIterator* aIter)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
JSStructuredCloneData data;
|
||||
if (!ReadParam(aMsg, aIter, &data)) {
|
||||
MOZ_ASSERT(!Data());
|
||||
|
||||
size_t dataLength = 0;
|
||||
if (!ReadParam(aMsg, aIter, &dataLength)) {
|
||||
return false;
|
||||
}
|
||||
mSharedData = new SharedJSAllocatedData(Move(data));
|
||||
mInitialized = true;
|
||||
|
||||
if (!dataLength) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mSharedData = SharedJSAllocatedData::AllocateForExternalData(dataLength);
|
||||
NS_ENSURE_TRUE(mSharedData, false);
|
||||
|
||||
if (!aMsg->ReadBytesInto(aIter, mSharedData->Data(), dataLength)) {
|
||||
mSharedData = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredCloneData::CopyExternalData(const char* aData,
|
||||
StructuredCloneData::CopyExternalData(const void* aData,
|
||||
size_t aDataLength)
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
MOZ_ASSERT(!Data());
|
||||
mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData,
|
||||
aDataLength);
|
||||
NS_ENSURE_TRUE(mSharedData, false);
|
||||
mInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,43 +24,54 @@ namespace ipc {
|
|||
class SharedJSAllocatedData final
|
||||
{
|
||||
public:
|
||||
explicit SharedJSAllocatedData(JSStructuredCloneData&& aData)
|
||||
: mData(Move(aData))
|
||||
{ }
|
||||
SharedJSAllocatedData(uint64_t* aData, size_t aDataLength)
|
||||
: mData(aData), mDataLength(aDataLength)
|
||||
{
|
||||
MOZ_ASSERT(mData);
|
||||
}
|
||||
|
||||
static already_AddRefed<SharedJSAllocatedData>
|
||||
CreateFromExternalData(const char* aData, size_t aDataLength)
|
||||
AllocateForExternalData(size_t aDataLength)
|
||||
{
|
||||
JSStructuredCloneData buf;
|
||||
buf.WriteBytes(aData, aDataLength);
|
||||
uint64_t* data = Allocate64bitSafely(aDataLength);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SharedJSAllocatedData> sharedData =
|
||||
new SharedJSAllocatedData(Move(buf));
|
||||
new SharedJSAllocatedData(data, aDataLength);
|
||||
return sharedData.forget();
|
||||
}
|
||||
|
||||
static already_AddRefed<SharedJSAllocatedData>
|
||||
CreateFromExternalData(const JSStructuredCloneData& aData)
|
||||
CreateFromExternalData(const void* aData, size_t aDataLength)
|
||||
{
|
||||
JSStructuredCloneData buf;
|
||||
auto iter = aData.Iter();
|
||||
while (!iter.Done()) {
|
||||
buf.WriteBytes(iter.Data(), iter.RemainingInSegment());
|
||||
iter.Advance(aData, iter.RemainingInSegment());
|
||||
}
|
||||
RefPtr<SharedJSAllocatedData> sharedData =
|
||||
new SharedJSAllocatedData(Move(buf));
|
||||
AllocateForExternalData(aDataLength);
|
||||
memcpy(sharedData->Data(), aData, aDataLength);
|
||||
return sharedData.forget();
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
|
||||
|
||||
JSStructuredCloneData& Data() { return mData; }
|
||||
size_t DataLength() const { return mData.Size(); }
|
||||
uint64_t* Data() const { return mData; }
|
||||
size_t DataLength() const { return mDataLength; }
|
||||
|
||||
private:
|
||||
~SharedJSAllocatedData() { }
|
||||
~SharedJSAllocatedData()
|
||||
{
|
||||
js_free(mData);
|
||||
}
|
||||
|
||||
JSStructuredCloneData mData;
|
||||
static uint64_t*
|
||||
Allocate64bitSafely(size_t aSize)
|
||||
{
|
||||
// Structured cloning requires 64-bit aligment.
|
||||
return static_cast<uint64_t*>(js_malloc(std::max(sizeof(uint64_t), aSize)));
|
||||
}
|
||||
|
||||
uint64_t* mData;
|
||||
size_t mDataLength;
|
||||
};
|
||||
|
||||
class StructuredCloneData : public StructuredCloneHolder
|
||||
|
@ -70,22 +81,20 @@ public:
|
|||
: StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
|
||||
StructuredCloneHolder::TransferringSupported,
|
||||
StructuredCloneHolder::DifferentProcess)
|
||||
, mInitialized(false)
|
||||
, mExternalData(nullptr)
|
||||
, mExternalDataLength(0)
|
||||
{}
|
||||
|
||||
StructuredCloneData(const StructuredCloneData&) = delete;
|
||||
|
||||
StructuredCloneData(StructuredCloneData&& aOther) = default;
|
||||
|
||||
~StructuredCloneData()
|
||||
{}
|
||||
{
|
||||
MOZ_ASSERT(!(mExternalData && mSharedData));
|
||||
}
|
||||
|
||||
StructuredCloneData&
|
||||
operator=(const StructuredCloneData& aOther) = delete;
|
||||
|
||||
StructuredCloneData&
|
||||
operator=(StructuredCloneData&& aOther) = default;
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& BlobImpls() const
|
||||
{
|
||||
return mBlobImplArray;
|
||||
|
@ -111,31 +120,23 @@ public:
|
|||
JS::Handle<JS::Value> aTransfers,
|
||||
ErrorResult &aRv);
|
||||
|
||||
bool UseExternalData(const JSStructuredCloneData& aData)
|
||||
void UseExternalData(uint64_t* aData, size_t aDataLength)
|
||||
{
|
||||
auto iter = aData.Iter();
|
||||
bool success = false;
|
||||
mExternalData =
|
||||
aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
|
||||
mInitialized = true;
|
||||
return success;
|
||||
MOZ_ASSERT(!Data());
|
||||
mExternalData = aData;
|
||||
mExternalDataLength = aDataLength;
|
||||
}
|
||||
|
||||
bool CopyExternalData(const char* aData, size_t aDataLength);
|
||||
bool CopyExternalData(const void* aData, size_t aDataLength);
|
||||
|
||||
JSStructuredCloneData& Data()
|
||||
{
|
||||
return mSharedData ? mSharedData->Data() : mExternalData;
|
||||
}
|
||||
|
||||
const JSStructuredCloneData& Data() const
|
||||
uint64_t* Data() const
|
||||
{
|
||||
return mSharedData ? mSharedData->Data() : mExternalData;
|
||||
}
|
||||
|
||||
size_t DataLength() const
|
||||
{
|
||||
return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
|
||||
return mSharedData ? mSharedData->DataLength() : mExternalDataLength;
|
||||
}
|
||||
|
||||
SharedJSAllocatedData* SharedData() const
|
||||
|
@ -148,9 +149,10 @@ public:
|
|||
bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
|
||||
|
||||
private:
|
||||
JSStructuredCloneData mExternalData;
|
||||
uint64_t* MOZ_NON_OWNING_REF mExternalData;
|
||||
size_t mExternalDataLength;
|
||||
|
||||
RefPtr<SharedJSAllocatedData> mSharedData;
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
|
|
|
@ -7,18 +7,14 @@ include protocol PBlob;
|
|||
|
||||
include DOMTypes;
|
||||
|
||||
using struct mozilla::SerializedStructuredCloneBuffer
|
||||
from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
||||
struct MessagePortMessage
|
||||
{
|
||||
SerializedStructuredCloneBuffer data;
|
||||
PBlob[] blobs;
|
||||
MessagePortIdentifier[] transferredPorts;
|
||||
uint8_t[] data;
|
||||
PBlob[] blobs;
|
||||
};
|
||||
|
||||
// This protocol is used for the MessageChannel/MessagePort API
|
||||
|
|
|
@ -20,6 +20,66 @@ using namespace ipc;
|
|||
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
SharedMessagePortMessage::Read(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mData.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* data = reinterpret_cast<uint64_t*>(mData.Elements());
|
||||
size_t dataLen = mData.Length();
|
||||
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||
|
||||
ReadFromBuffer(aParent, aCx, data, dataLen, aValue, aRv);
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
|
||||
Free();
|
||||
}
|
||||
|
||||
void
|
||||
SharedMessagePortMessage::Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
JS::Handle<JS::Value> aTransfer,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
StructuredCloneHolder::Write(aCx, aValue, aTransfer, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> cloneData;
|
||||
|
||||
MoveBufferDataToArray(cloneData, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mData.IsEmpty());
|
||||
mData.SwapElements(cloneData);
|
||||
}
|
||||
|
||||
void
|
||||
SharedMessagePortMessage::Free()
|
||||
{
|
||||
if (!mData.IsEmpty()) {
|
||||
auto* data = reinterpret_cast<uint64_t*>(mData.Elements());
|
||||
size_t dataLen = mData.Length();
|
||||
MOZ_ASSERT(!(dataLen % sizeof(*data)));
|
||||
|
||||
FreeBuffer(data, dataLen);
|
||||
mData.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
SharedMessagePortMessage::~SharedMessagePortMessage()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
SharedMessagePortMessage::FromSharedToMessagesChild(
|
||||
MessagePortChild* aActor,
|
||||
|
@ -35,8 +95,7 @@ SharedMessagePortMessage::FromSharedToMessagesChild(
|
|||
|
||||
for (auto& data : aData) {
|
||||
MessagePortMessage* message = aArray.AppendElement();
|
||||
data->mBuffer->abandon();
|
||||
data->mBuffer->steal(&message->data().data);
|
||||
message->data().SwapElements(data->mData);
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
|
||||
if (!blobImpls.IsEmpty()) {
|
||||
|
@ -68,9 +127,7 @@ SharedMessagePortMessage::FromMessagesToSharedChild(
|
|||
for (auto& message : aArray) {
|
||||
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||
|
||||
data->mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>();
|
||||
data->mBuffer->adopt(Move(message.data().data), JS_STRUCTURED_CLONE_VERSION,
|
||||
&StructuredCloneHolder::sCallbacks, data.get());
|
||||
data->mData.SwapElements(message.data());
|
||||
|
||||
const nsTArray<PBlobChild*>& blobs = message.blobsChild();
|
||||
if (!blobs.IsEmpty()) {
|
||||
|
@ -110,8 +167,7 @@ SharedMessagePortMessage::FromSharedToMessagesParent(
|
|||
|
||||
for (auto& data : aData) {
|
||||
MessagePortMessage* message = aArray.AppendElement(mozilla::fallible);
|
||||
data->mBuffer->abandon();
|
||||
data->mBuffer->steal(&message->data().data);
|
||||
message->data().SwapElements(data->mData);
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
|
||||
if (!blobImpls.IsEmpty()) {
|
||||
|
@ -145,9 +201,7 @@ SharedMessagePortMessage::FromMessagesToSharedParent(
|
|||
for (auto& message : aArray) {
|
||||
RefPtr<SharedMessagePortMessage> data = new SharedMessagePortMessage();
|
||||
|
||||
data->mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>();
|
||||
data->mBuffer->adopt(Move(message.data().data), JS_STRUCTURED_CLONE_VERSION,
|
||||
&StructuredCloneHolder::sCallbacks, data.get());
|
||||
data->mData.SwapElements(message.data());
|
||||
|
||||
const nsTArray<PBlobParent*>& blobs = message.blobsParent();
|
||||
if (!blobs.IsEmpty()) {
|
||||
|
|
|
@ -20,11 +20,25 @@ class SharedMessagePortMessage final : public StructuredCloneHolder
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage)
|
||||
|
||||
nsTArray<uint8_t> mData;
|
||||
|
||||
SharedMessagePortMessage()
|
||||
: StructuredCloneHolder(CloningSupported, TransferringSupported,
|
||||
DifferentProcess)
|
||||
{}
|
||||
|
||||
void Read(nsISupports* aParent,
|
||||
JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Write(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
JS::Handle<JS::Value> aTransfer,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Free();
|
||||
|
||||
static void
|
||||
FromSharedToMessagesChild(
|
||||
MessagePortChild* aActor,
|
||||
|
@ -48,7 +62,7 @@ public:
|
|||
FallibleTArray<RefPtr<SharedMessagePortMessage>>& aData);
|
||||
|
||||
private:
|
||||
~SharedMessagePortMessage() {}
|
||||
~SharedMessagePortMessage();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#ifndef mozilla_dom_TCPSocketChild_h
|
||||
#define mozilla_dom_TCPSocketChild_h
|
||||
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/net/PTCPSocketChild.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
|
|
@ -425,32 +425,6 @@ bool Pickle::FlattenBytes(PickleIterator* iter, const char** data, uint32_t leng
|
|||
return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
|
||||
}
|
||||
|
||||
bool Pickle::ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buffers,
|
||||
uint32_t alignment) const
|
||||
{
|
||||
DCHECK(iter);
|
||||
DCHECK(buffers);
|
||||
DCHECK(alignment == 4 || alignment == 8);
|
||||
DCHECK(intptr_t(header_) % alignment == 0);
|
||||
|
||||
if (AlignInt(length) < length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t padding_len = intptr_t(iter->iter_.Data()) % alignment;
|
||||
if (!iter->iter_.AdvanceAcrossSegments(buffers_, padding_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success;
|
||||
*buffers = const_cast<BufferList*>(&buffers_)->Extract(iter->iter_, length, &success);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
|
||||
}
|
||||
|
||||
bool Pickle::ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const {
|
||||
if (AlignInt(length) < length) {
|
||||
return false;
|
||||
|
|
|
@ -109,8 +109,6 @@ class Pickle {
|
|||
MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const;
|
||||
MOZ_MUST_USE bool FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
|
||||
uint32_t alignment = sizeof(memberAlignmentType));
|
||||
MOZ_MUST_USE bool ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buffers,
|
||||
uint32_t alignment = sizeof(memberAlignmentType)) const;
|
||||
|
||||
// Safer version of ReadInt() checks for the result not being negative.
|
||||
// Use it for reading the object sizes.
|
||||
|
|
|
@ -64,31 +64,21 @@ struct null_t {
|
|||
bool operator==(const null_t&) const { return true; }
|
||||
};
|
||||
|
||||
struct SerializedStructuredCloneBuffer final
|
||||
struct MOZ_STACK_CLASS SerializedStructuredCloneBuffer
|
||||
{
|
||||
SerializedStructuredCloneBuffer&
|
||||
operator=(const SerializedStructuredCloneBuffer& aOther)
|
||||
{
|
||||
data.Clear();
|
||||
auto iter = aOther.data.Iter();
|
||||
while (!iter.Done()) {
|
||||
data.WriteBytes(iter.Data(), iter.RemainingInSegment());
|
||||
iter.Advance(aOther.data, iter.RemainingInSegment());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SerializedStructuredCloneBuffer()
|
||||
: data(nullptr), dataLength(0)
|
||||
{ }
|
||||
|
||||
bool
|
||||
operator==(const SerializedStructuredCloneBuffer& aOther) const
|
||||
{
|
||||
// The copy assignment operator and the equality operator are
|
||||
// needed by the IPDL generated code. We relied on the copy
|
||||
// assignment operator at some places but we never use the
|
||||
// equality operator.
|
||||
return false;
|
||||
return this->data == aOther.data &&
|
||||
this->dataLength == aOther.dataLength;
|
||||
}
|
||||
|
||||
JSStructuredCloneData data;
|
||||
uint64_t* data;
|
||||
size_t dataLength;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -713,55 +703,6 @@ struct ParamTraits<mozilla::net::WebSocketFrameData>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<JSStructuredCloneData>
|
||||
{
|
||||
typedef JSStructuredCloneData paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
MOZ_ASSERT(!(aParam.Size() % sizeof(uint64_t)));
|
||||
WriteParam(aMsg, aParam.Size());
|
||||
auto iter = aParam.Iter();
|
||||
while (!iter.Done()) {
|
||||
aMsg->WriteBytes(iter.Data(), iter.RemainingInSegment(), sizeof(uint64_t));
|
||||
iter.Advance(aParam, iter.RemainingInSegment());
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
size_t length = 0;
|
||||
if (!ReadParam(aMsg, aIter, &length)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(!(length % sizeof(uint64_t)));
|
||||
|
||||
mozilla::BufferList<InfallibleAllocPolicy> buffers(0, 0, 4096);
|
||||
|
||||
// Borrowing is not suitable to use for IPC to hand out data
|
||||
// because we often want to store the data somewhere for
|
||||
// processing after IPC has released the underlying buffers. One
|
||||
// case is PContentChild::SendGetXPCOMProcessAttributes. We can't
|
||||
// return a borrowed buffer because the out param outlives the
|
||||
// IPDL callback.
|
||||
if (length && !aMsg->ExtractBuffers(aIter, length, &buffers, sizeof(uint64_t))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success;
|
||||
mozilla::BufferList<js::SystemAllocPolicy> out =
|
||||
buffers.MoveFallible<js::SystemAllocPolicy>(&success);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aResult = JSStructuredCloneData(Move(out));
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
|
||||
{
|
||||
|
@ -769,17 +710,38 @@ struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
|
|||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.data);
|
||||
WriteParam(aMsg, aParam.dataLength);
|
||||
if (aParam.dataLength) {
|
||||
// Structured clone data must be 64-bit aligned.
|
||||
aMsg->WriteBytes(aParam.data, aParam.dataLength, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
return ReadParam(aMsg, aIter, &aResult->data);
|
||||
if (!ReadParam(aMsg, aIter, &aResult->dataLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aResult->dataLength) {
|
||||
aResult->data = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char** buffer =
|
||||
const_cast<const char**>(reinterpret_cast<char**>(&aResult->data));
|
||||
// Structured clone data must be 64-bit aligned.
|
||||
if (!const_cast<Message*>(aMsg)->FlattenBytes(aIter, buffer, aResult->dataLength,
|
||||
sizeof(uint64_t))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Log(const paramType& aParam, std::wstring* aLog)
|
||||
{
|
||||
LogParam(aParam.data.Size(), aLog);
|
||||
LogParam(aParam.dataLength, aLog);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
#ifndef js_StructuredClone_h
|
||||
#define js_StructuredClone_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BufferList.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "jstypes.h"
|
||||
|
@ -126,9 +123,9 @@ typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
|
|||
uint64_t* extraData);
|
||||
|
||||
/**
|
||||
* Called when freeing an unknown transferable object. Note that it
|
||||
* should never trigger a garbage collection (and will assert in a
|
||||
* debug build if it does.)
|
||||
* Called when JS_ClearStructuredClone has to free an unknown transferable
|
||||
* object. Note that it should never trigger a garbage collection (and will
|
||||
* assert in a debug build if it does.)
|
||||
*/
|
||||
typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
|
||||
void* content, uint64_t extraData, void* closure);
|
||||
|
@ -148,69 +145,28 @@ struct JSStructuredCloneCallbacks {
|
|||
FreeTransferStructuredCloneOp freeTransfer;
|
||||
};
|
||||
|
||||
enum OwnTransferablePolicy {
|
||||
OwnsTransferablesIfAny,
|
||||
IgnoreTransferablesIfAny,
|
||||
NoTransferables
|
||||
};
|
||||
|
||||
class MOZ_NON_MEMMOVABLE JSStructuredCloneData : public mozilla::BufferList<js::SystemAllocPolicy>
|
||||
{
|
||||
typedef js::SystemAllocPolicy AllocPolicy;
|
||||
typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
|
||||
|
||||
static const size_t kInitialSize = 0;
|
||||
static const size_t kInitialCapacity = 4096;
|
||||
static const size_t kStandardCapacity = 4096;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks_;
|
||||
void* closure_;
|
||||
OwnTransferablePolicy ownTransferables_;
|
||||
|
||||
void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure,
|
||||
OwnTransferablePolicy policy) {
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = policy;
|
||||
}
|
||||
|
||||
friend struct JSStructuredCloneWriter;
|
||||
friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
|
||||
|
||||
public:
|
||||
explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
|
||||
: BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
|
||||
, callbacks_(nullptr)
|
||||
, closure_(nullptr)
|
||||
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
|
||||
{}
|
||||
MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
|
||||
: BufferList(Move(buffers))
|
||||
, callbacks_(nullptr)
|
||||
, closure_(nullptr)
|
||||
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
|
||||
{}
|
||||
JSStructuredCloneData(JSStructuredCloneData&& other) = default;
|
||||
JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
|
||||
~JSStructuredCloneData();
|
||||
|
||||
using BufferList::BufferList;
|
||||
};
|
||||
|
||||
/** Note: if the *data contains transferable objects, it can be read only once. */
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version,
|
||||
JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t version,
|
||||
JS::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
|
||||
|
||||
/**
|
||||
* Note: On success, the caller is responsible for calling
|
||||
* JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure).
|
||||
*/
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data,
|
||||
JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size_t* nbytesp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* closure, JS::HandleValue transferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable);
|
||||
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void *closure, bool freeData = true);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
|
||||
|
@ -218,34 +174,43 @@ JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
|
|||
|
||||
/** RAII sugar for JS_WriteStructuredClone. */
|
||||
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
JSStructuredCloneData data_;
|
||||
uint64_t* data_;
|
||||
size_t nbytes_;
|
||||
uint32_t version_;
|
||||
enum {
|
||||
OwnsTransferablesIfAny,
|
||||
IgnoreTransferablesIfAny,
|
||||
NoTransferables
|
||||
} ownTransferables_;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks_;
|
||||
void* closure_;
|
||||
|
||||
public:
|
||||
JSAutoStructuredCloneBuffer()
|
||||
: version_(JS_STRUCTURED_CLONE_VERSION)
|
||||
{
|
||||
data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
|
||||
}
|
||||
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
|
||||
ownTransferables_(NoTransferables),
|
||||
callbacks_(nullptr), closure_(nullptr)
|
||||
{}
|
||||
|
||||
JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks* callbacks, void* closure)
|
||||
: version_(JS_STRUCTURED_CLONE_VERSION)
|
||||
{
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
|
||||
}
|
||||
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
|
||||
ownTransferables_(NoTransferables),
|
||||
callbacks_(callbacks), closure_(closure)
|
||||
{}
|
||||
|
||||
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
|
||||
JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
|
||||
|
||||
~JSAutoStructuredCloneBuffer() { clear(); }
|
||||
|
||||
JSStructuredCloneData& data() { return data_; }
|
||||
bool empty() const { return !data_.Size(); }
|
||||
uint64_t* data() const { return data_; }
|
||||
size_t nbytes() const { return nbytes_; }
|
||||
|
||||
void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
/** Copy some memory. It will be automatically freed by the destructor. */
|
||||
bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
/**
|
||||
|
@ -253,22 +218,24 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
|||
* data must have been allocated by the JS engine (e.g., extracted via
|
||||
* JSAutoStructuredCloneBuffer::steal).
|
||||
*/
|
||||
void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
/**
|
||||
* Release the buffer and transfer ownership to the caller.
|
||||
* Release the buffer and transfer ownership to the caller. The caller is
|
||||
* responsible for calling JS_ClearStructuredClone or feeding the memory
|
||||
* back to JSAutoStructuredCloneBuffer::adopt.
|
||||
*/
|
||||
void steal(JSStructuredCloneData* data, uint32_t* versionp=nullptr,
|
||||
void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr,
|
||||
const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr);
|
||||
|
||||
/**
|
||||
* Abandon ownership of any transferable objects stored in the buffer,
|
||||
* without freeing the buffer itself. Useful when copying the data out into
|
||||
* an external container, though note that you will need to use adopt() to
|
||||
* properly release that data eventually.
|
||||
* an external container, though note that you will need to use adopt() or
|
||||
* JS_ClearStructuredClone to properly release that data eventually.
|
||||
*/
|
||||
void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; }
|
||||
void abandon() { ownTransferables_ = IgnoreTransferablesIfAny; }
|
||||
|
||||
bool read(JSContext* cx, JS::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
|
||||
|
|
|
@ -2075,31 +2075,36 @@ class CloneBufferObject : public NativeObject {
|
|||
Rooted<CloneBufferObject*> obj(cx, Create(cx));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
auto data = js::MakeUnique<JSStructuredCloneData>();
|
||||
if (!data) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
buffer->steal(data.get());
|
||||
obj->setData(data.release());
|
||||
uint64_t* datap;
|
||||
size_t nbytes;
|
||||
buffer->steal(&datap, &nbytes);
|
||||
obj->setData(datap);
|
||||
obj->setNBytes(nbytes);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSStructuredCloneData* data() const {
|
||||
return static_cast<JSStructuredCloneData*>(getReservedSlot(DATA_SLOT).toPrivate());
|
||||
uint64_t* data() const {
|
||||
return static_cast<uint64_t*>(getReservedSlot(DATA_SLOT).toPrivate());
|
||||
}
|
||||
|
||||
void setData(JSStructuredCloneData* aData) {
|
||||
void setData(uint64_t* aData) {
|
||||
MOZ_ASSERT(!data());
|
||||
setReservedSlot(DATA_SLOT, PrivateValue(aData));
|
||||
}
|
||||
|
||||
size_t nbytes() const {
|
||||
return getReservedSlot(LENGTH_SLOT).toInt32();
|
||||
}
|
||||
|
||||
void setNBytes(size_t nbytes) {
|
||||
MOZ_ASSERT(nbytes <= UINT32_MAX);
|
||||
setReservedSlot(LENGTH_SLOT, Int32Value(nbytes));
|
||||
}
|
||||
|
||||
// Discard an owned clone buffer.
|
||||
void discard() {
|
||||
if (data()) {
|
||||
JSAutoStructuredCloneBuffer clonebuf;
|
||||
clonebuf.adopt(Move(*data()));
|
||||
}
|
||||
if (data())
|
||||
JS_ClearStructuredClone(data(), nbytes(), nullptr, nullptr);
|
||||
setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
|
||||
}
|
||||
|
||||
|
@ -2126,12 +2131,8 @@ class CloneBufferObject : public NativeObject {
|
|||
char* str = JS_EncodeString(cx, args[0].toString());
|
||||
if (!str)
|
||||
return false;
|
||||
size_t nbytes = JS_GetStringLength(args[0].toString());
|
||||
MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0);
|
||||
auto buf = js::MakeUnique<JSStructuredCloneData>(nbytes, nbytes, nbytes);
|
||||
js_memcpy(buf->Start(), str, nbytes);
|
||||
JS_free(cx, str);
|
||||
obj->setData(buf.release());
|
||||
obj->setData(reinterpret_cast<uint64_t*>(str));
|
||||
obj->setNBytes(JS_GetStringLength(args[0].toString()));
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
|
@ -2159,7 +2160,7 @@ class CloneBufferObject : public NativeObject {
|
|||
}
|
||||
|
||||
bool hasTransferable;
|
||||
if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
|
||||
if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
|
||||
return false;
|
||||
|
||||
if (hasTransferable) {
|
||||
|
@ -2167,11 +2168,7 @@ class CloneBufferObject : public NativeObject {
|
|||
return false;
|
||||
}
|
||||
|
||||
const char* buffer;
|
||||
size_t size = obj->data()->Size();
|
||||
auto iter = obj->data()->Iter();
|
||||
obj->data()->FlattenBytes(iter, &buffer, size);
|
||||
JSString* str = JS_NewStringCopyN(cx, buffer, size);
|
||||
JSString* str = JS_NewStringCopyN(cx, reinterpret_cast<char*>(obj->data()), obj->nbytes());
|
||||
if (!str)
|
||||
return false;
|
||||
args.rval().setString(str);
|
||||
|
@ -2252,11 +2249,11 @@ Deserialize(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
bool hasTransferable;
|
||||
if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
|
||||
if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
|
||||
return false;
|
||||
|
||||
RootedValue deserialized(cx);
|
||||
if (!JS_ReadStructuredClone(cx, *obj->data(),
|
||||
if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(),
|
||||
JS_STRUCTURED_CLONE_VERSION, &deserialized, nullptr, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -151,60 +151,6 @@ PairToUInt64(uint32_t tag, uint32_t data)
|
|||
|
||||
namespace js {
|
||||
|
||||
template<typename T, typename AllocPolicy>
|
||||
struct BufferIterator {
|
||||
typedef mozilla::BufferList<AllocPolicy> BufferList;
|
||||
|
||||
explicit BufferIterator(BufferList& buffer)
|
||||
: mBuffer(buffer)
|
||||
, mIter(buffer.Iter())
|
||||
{
|
||||
JS_STATIC_ASSERT(8 % sizeof(T) == 0);
|
||||
}
|
||||
|
||||
BufferIterator operator++(int) {
|
||||
BufferIterator ret = *this;
|
||||
if (!mIter.AdvanceAcrossSegments(mBuffer, sizeof(T))) {
|
||||
MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
BufferIterator& operator+=(size_t size) {
|
||||
if (!mIter.AdvanceAcrossSegments(mBuffer, size)) {
|
||||
MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void next() {
|
||||
if (!mIter.AdvanceAcrossSegments(mBuffer, sizeof(T))) {
|
||||
MOZ_ASSERT(false, "Failed to read StructuredCloneData. Data incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
bool done() const {
|
||||
return mIter.Done();
|
||||
}
|
||||
|
||||
bool readBytes(char* outData, size_t size) {
|
||||
return mBuffer.ReadBytes(mIter, outData, size);
|
||||
}
|
||||
|
||||
void write(const T& data) {
|
||||
MOZ_ASSERT(mIter.HasRoomFor(sizeof(T)));
|
||||
*reinterpret_cast<T*>(mIter.Data()) = data;
|
||||
}
|
||||
|
||||
T peek() const {
|
||||
MOZ_ASSERT(mIter.HasRoomFor(sizeof(T)));
|
||||
return *reinterpret_cast<T*>(mIter.Data());
|
||||
}
|
||||
|
||||
BufferList& mBuffer;
|
||||
typename BufferList::IterImpl mIter;
|
||||
};
|
||||
|
||||
struct SCOutput {
|
||||
public:
|
||||
explicit SCOutput(JSContext* cx);
|
||||
|
@ -222,29 +168,24 @@ struct SCOutput {
|
|||
template <class T>
|
||||
bool writeArray(const T* p, size_t nbytes);
|
||||
|
||||
bool extractBuffer(JSStructuredCloneData* data);
|
||||
void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure);
|
||||
bool extractBuffer(uint64_t** datap, size_t* sizep);
|
||||
|
||||
uint64_t count() const { return buf.Size() / sizeof(uint64_t); }
|
||||
BufferIterator<uint64_t, TempAllocPolicy> iter() {
|
||||
return BufferIterator<uint64_t, TempAllocPolicy>(buf);
|
||||
}
|
||||
uint64_t count() const { return buf.length(); }
|
||||
uint64_t* rawBuffer() { return buf.begin(); }
|
||||
|
||||
private:
|
||||
JSContext* cx;
|
||||
mozilla::BufferList<TempAllocPolicy> buf;
|
||||
Vector<uint64_t> buf;
|
||||
};
|
||||
|
||||
class SCInput {
|
||||
typedef js::BufferIterator<uint64_t, SystemAllocPolicy> BufferIterator;
|
||||
|
||||
public:
|
||||
SCInput(JSContext* cx, JSStructuredCloneData& data);
|
||||
SCInput(JSContext* cx, uint64_t* data, size_t nbytes);
|
||||
|
||||
JSContext* context() const { return cx; }
|
||||
|
||||
static void getPtr(uint64_t data, void** ptr);
|
||||
static void getPair(uint64_t data, uint32_t* tagp, uint32_t* datap);
|
||||
static void getPtr(const uint64_t* buffer, void** ptr);
|
||||
static void getPair(const uint64_t* buffer, uint32_t* tagp, uint32_t* datap);
|
||||
|
||||
bool read(uint64_t* p);
|
||||
bool readNativeEndian(uint64_t* p);
|
||||
|
@ -258,7 +199,8 @@ class SCInput {
|
|||
bool get(uint64_t* p);
|
||||
bool getPair(uint32_t* tagp, uint32_t* datap);
|
||||
|
||||
BufferIterator tell() const { return point; }
|
||||
uint64_t* tell() const { return point; }
|
||||
uint64_t* end() const { return bufEnd; }
|
||||
|
||||
template <class T>
|
||||
bool readArray(T* p, size_t nelems);
|
||||
|
@ -276,7 +218,8 @@ class SCInput {
|
|||
}
|
||||
|
||||
JSContext* cx;
|
||||
BufferIterator point;
|
||||
uint64_t* point;
|
||||
uint64_t* bufEnd;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -353,13 +296,8 @@ struct JSStructuredCloneWriter {
|
|||
|
||||
SCOutput& output() { return out; }
|
||||
|
||||
bool extractBuffer(JSStructuredCloneData* data) {
|
||||
bool success = out.extractBuffer(data);
|
||||
if (success) {
|
||||
data->setOptionalCallbacks(callbacks, closure,
|
||||
OwnTransferablePolicy::OwnsTransferablesIfAny);
|
||||
}
|
||||
return success;
|
||||
bool extractBuffer(uint64_t** datap, size_t* sizep) {
|
||||
return out.extractBuffer(datap, sizep);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -472,19 +410,19 @@ ReportDataCloneError(JSContext* cx,
|
|||
}
|
||||
|
||||
bool
|
||||
WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp,
|
||||
WriteStructuredClone(JSContext* cx, HandleValue v, uint64_t** bufp, size_t* nbytesp,
|
||||
const JSStructuredCloneCallbacks* cb, void* cbClosure,
|
||||
Value transferable)
|
||||
{
|
||||
JSStructuredCloneWriter w(cx, cb, cbClosure, transferable);
|
||||
return w.init() && w.write(v) && w.extractBuffer(bufp);
|
||||
return w.init() && w.write(v) && w.extractBuffer(bufp, nbytesp);
|
||||
}
|
||||
|
||||
bool
|
||||
ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, MutableHandleValue vp,
|
||||
ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks* cb, void* cbClosure)
|
||||
{
|
||||
SCInput in(cx, data);
|
||||
SCInput in(cx, data, nbytes);
|
||||
JSStructuredCloneReader r(in, cb, cbClosure);
|
||||
return r.read(vp);
|
||||
}
|
||||
|
@ -492,18 +430,18 @@ ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, MutableHandleVal
|
|||
// If the given buffer contains Transferables, free them. Note that custom
|
||||
// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
|
||||
// delete their transferables.
|
||||
template<typename AllocPolicy>
|
||||
static void
|
||||
DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
|
||||
DiscardTransferables(uint64_t* buffer, size_t nbytes,
|
||||
const JSStructuredCloneCallbacks* cb, void* cbClosure)
|
||||
{
|
||||
auto point = BufferIterator<uint64_t, AllocPolicy>(buffer);
|
||||
if (point.done())
|
||||
MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0);
|
||||
uint64_t* end = buffer + nbytes / sizeof(uint64_t);
|
||||
uint64_t* point = buffer;
|
||||
if (point == end)
|
||||
return; // Empty buffer
|
||||
|
||||
uint32_t tag, data;
|
||||
SCInput::getPair(point.peek(), &tag, &data);
|
||||
point.next();
|
||||
SCInput::getPair(point++, &tag, &data);
|
||||
if (tag != SCTAG_TRANSFER_MAP_HEADER)
|
||||
return;
|
||||
|
||||
|
@ -513,30 +451,26 @@ DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
|
|||
// freeTransfer should not GC
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
|
||||
if (point.done())
|
||||
if (point == end)
|
||||
return;
|
||||
|
||||
uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
|
||||
point.next();
|
||||
uint64_t numTransferables = LittleEndian::readUint64(point++);
|
||||
while (numTransferables--) {
|
||||
if (point.done())
|
||||
if (point == end)
|
||||
return;
|
||||
|
||||
uint32_t ownership;
|
||||
SCInput::getPair(point.peek(), &tag, &ownership);
|
||||
point.next();
|
||||
SCInput::getPair(point++, &tag, &ownership);
|
||||
MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
|
||||
if (point.done())
|
||||
if (point == end)
|
||||
return;
|
||||
|
||||
void* content;
|
||||
SCInput::getPtr(point.peek(), &content);
|
||||
point.next();
|
||||
if (point.done())
|
||||
SCInput::getPtr(point++, &content);
|
||||
if (point == end)
|
||||
return;
|
||||
|
||||
uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
|
||||
point.next();
|
||||
uint64_t extraData = LittleEndian::readUint64(point++);
|
||||
|
||||
if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
|
||||
continue;
|
||||
|
@ -558,51 +492,46 @@ DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
|
|||
}
|
||||
|
||||
static bool
|
||||
StructuredCloneHasTransferObjects(const JSStructuredCloneData& data)
|
||||
StructuredCloneHasTransferObjects(const uint64_t* data, size_t nbytes)
|
||||
{
|
||||
auto iter = data.Iter();
|
||||
|
||||
if (data.Size() < sizeof(uint64_t))
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
uint64_t u;
|
||||
data.ReadBytes(iter, reinterpret_cast<char*>(&u), sizeof(u));
|
||||
uint64_t u = LittleEndian::readUint64(data);
|
||||
uint32_t tag = uint32_t(u >> 32);
|
||||
return (tag == SCTAG_TRANSFER_MAP_HEADER);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
SCInput::SCInput(JSContext* cx, JSStructuredCloneData& data)
|
||||
: cx(cx), point(data)
|
||||
SCInput::SCInput(JSContext* cx, uint64_t* data, size_t nbytes)
|
||||
: cx(cx), point(data), bufEnd(data + nbytes / 8)
|
||||
{
|
||||
|
||||
static_assert(JSStructuredCloneData::kSegmentAlignment % 8 == 0,
|
||||
"structured clone buffer reads should be aligned");
|
||||
MOZ_ASSERT(data.Size() % 8 == 0);
|
||||
// On 32-bit, we sometimes construct an SCInput from an SCOutput buffer,
|
||||
// which is not guaranteed to be 8-byte aligned
|
||||
MOZ_ASSERT((uintptr_t(data) & (sizeof(int) - 1)) == 0);
|
||||
MOZ_ASSERT((nbytes & 7) == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::read(uint64_t* p)
|
||||
{
|
||||
if (point.done()) {
|
||||
if (point == bufEnd) {
|
||||
*p = 0; /* initialize to shut GCC up */
|
||||
return reportTruncated();
|
||||
}
|
||||
*p = NativeEndian::swapFromLittleEndian(point.peek());
|
||||
point.next();
|
||||
*p = LittleEndian::readUint64(point++);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readNativeEndian(uint64_t* p)
|
||||
{
|
||||
if (point.done()) {
|
||||
if (point == bufEnd) {
|
||||
*p = 0; /* initialize to shut GCC up */
|
||||
return reportTruncated();
|
||||
}
|
||||
*p = point.peek();
|
||||
point.next();
|
||||
*p = *(point++);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -621,9 +550,9 @@ SCInput::readPair(uint32_t* tagp, uint32_t* datap)
|
|||
bool
|
||||
SCInput::get(uint64_t* p)
|
||||
{
|
||||
if (point.done())
|
||||
if (point == bufEnd)
|
||||
return reportTruncated();
|
||||
*p = NativeEndian::swapFromLittleEndian(point.peek());
|
||||
*p = LittleEndian::readUint64(point);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -640,9 +569,9 @@ SCInput::getPair(uint32_t* tagp, uint32_t* datap)
|
|||
}
|
||||
|
||||
void
|
||||
SCInput::getPair(uint64_t data, uint32_t* tagp, uint32_t* datap)
|
||||
SCInput::getPair(const uint64_t* p, uint32_t* tagp, uint32_t* datap)
|
||||
{
|
||||
uint64_t u = NativeEndian::swapFromLittleEndian(data);
|
||||
uint64_t u = LittleEndian::readUint64(p);
|
||||
*tagp = uint32_t(u >> 32);
|
||||
*datap = uint32_t(u);
|
||||
}
|
||||
|
@ -662,24 +591,23 @@ SCInput::readDouble(double* p)
|
|||
|
||||
template <typename T>
|
||||
static void
|
||||
swapFromLittleEndianInPlace(T* ptr, size_t nelems)
|
||||
copyAndSwapFromLittleEndian(T* dest, const void* src, size_t nelems)
|
||||
{
|
||||
if (nelems > 0)
|
||||
NativeEndian::swapFromLittleEndianInPlace(ptr, nelems);
|
||||
NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems);
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
swapFromLittleEndianInPlace(uint8_t* ptr, size_t nelems)
|
||||
{}
|
||||
copyAndSwapFromLittleEndian(uint8_t* dest, const void* src, size_t nelems)
|
||||
{
|
||||
memcpy(dest, src, nelems);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
SCInput::readArray(T* p, size_t nelems)
|
||||
{
|
||||
if (!nelems)
|
||||
return true;
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
|
||||
|
||||
/*
|
||||
|
@ -687,17 +615,11 @@ SCInput::readArray(T* p, size_t nelems)
|
|||
* larger than the remaining data.
|
||||
*/
|
||||
size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
|
||||
if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems)
|
||||
if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems || nwords > size_t(bufEnd - point))
|
||||
return reportTruncated();
|
||||
|
||||
size_t size = sizeof(T) * nelems;
|
||||
if (!point.readBytes(reinterpret_cast<char*>(p), size))
|
||||
return false;
|
||||
|
||||
swapFromLittleEndianInPlace(p, nelems);
|
||||
|
||||
point += sizeof(uint64_t) * nwords - size;
|
||||
|
||||
copyAndSwapFromLittleEndian(p, point, nelems);
|
||||
point += nwords;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -722,11 +644,11 @@ SCInput::readChars(char16_t* p, size_t nchars)
|
|||
}
|
||||
|
||||
void
|
||||
SCInput::getPtr(uint64_t data, void** ptr)
|
||||
SCInput::getPtr(const uint64_t* p, void** ptr)
|
||||
{
|
||||
// No endianness conversion is used for pointers, since they are not sent
|
||||
// across address spaces anyway.
|
||||
*ptr = reinterpret_cast<void*>(data);
|
||||
*ptr = reinterpret_cast<void*>(*p);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -739,17 +661,12 @@ SCInput::readPtr(void** p)
|
|||
return true;
|
||||
}
|
||||
|
||||
SCOutput::SCOutput(JSContext* cx)
|
||||
: cx(cx)
|
||||
, buf(0, 0, 4096, cx)
|
||||
{
|
||||
}
|
||||
SCOutput::SCOutput(JSContext* cx) : cx(cx), buf(cx) {}
|
||||
|
||||
bool
|
||||
SCOutput::write(uint64_t u)
|
||||
{
|
||||
uint64_t v = NativeEndian::swapToLittleEndian(u);
|
||||
return buf.WriteBytes(reinterpret_cast<char*>(&v), sizeof(u));
|
||||
return buf.append(NativeEndian::swapToLittleEndian(u));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -780,25 +697,26 @@ SCOutput::writeDouble(double d)
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
static T
|
||||
swapToLittleEndian(T value)
|
||||
static void
|
||||
copyAndSwapToLittleEndian(void* dest, const T* src, size_t nelems)
|
||||
{
|
||||
return NativeEndian::swapToLittleEndian(value);
|
||||
if (nelems > 0)
|
||||
NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems);
|
||||
}
|
||||
|
||||
template <>
|
||||
uint8_t
|
||||
swapToLittleEndian(uint8_t value)
|
||||
void
|
||||
copyAndSwapToLittleEndian(void* dest, const uint8_t* src, size_t nelems)
|
||||
{
|
||||
return value;
|
||||
memcpy(dest, src, nelems);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
SCOutput::writeArray(const T* p, size_t nelems)
|
||||
{
|
||||
JS_STATIC_ASSERT(8 % sizeof(T) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
|
||||
MOZ_ASSERT(8 % sizeof(T) == 0);
|
||||
MOZ_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
|
||||
|
||||
if (nelems == 0)
|
||||
return true;
|
||||
|
@ -807,22 +725,15 @@ SCOutput::writeArray(const T* p, size_t nelems)
|
|||
ReportAllocationOverflow(context());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nelems; i++) {
|
||||
T value = swapToLittleEndian(p[i]);
|
||||
if (!buf.WriteBytes(reinterpret_cast<char*>(&value), sizeof(value)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// zero-pad to 8 bytes boundary
|
||||
size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
|
||||
size_t padbytes = sizeof(uint64_t) * nwords - sizeof(T) * nelems;
|
||||
char zero = 0;
|
||||
for (size_t i = 0; i < padbytes; i++) {
|
||||
if (!buf.WriteBytes(&zero, sizeof(zero)))
|
||||
return false;
|
||||
}
|
||||
size_t start = buf.length();
|
||||
if (!buf.growByUninitialized(nwords))
|
||||
return false;
|
||||
|
||||
buf.back() = 0; /* zero-pad to an 8-byte boundary */
|
||||
|
||||
T* q = (T*) &buf[start];
|
||||
copyAndSwapToLittleEndian(q, p, nelems);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -855,42 +766,27 @@ SCOutput::writePtr(const void* p)
|
|||
}
|
||||
|
||||
bool
|
||||
SCOutput::extractBuffer(JSStructuredCloneData* data)
|
||||
SCOutput::extractBuffer(uint64_t** datap, size_t* sizep)
|
||||
{
|
||||
bool success;
|
||||
mozilla::BufferList<SystemAllocPolicy> out =
|
||||
buf.MoveFallible<SystemAllocPolicy>(&success);
|
||||
if (!success) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
*data = JSStructuredCloneData(Move(out));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure)
|
||||
{
|
||||
DiscardTransferables(buf, cb, cbClosure);
|
||||
*sizep = buf.length() * sizeof(uint64_t);
|
||||
return (*datap = buf.extractOrCopyRawBuffer()) != nullptr;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
JSStructuredCloneData::~JSStructuredCloneData()
|
||||
{
|
||||
if (!Size())
|
||||
return;
|
||||
if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
|
||||
DiscardTransferables(*this, callbacks_, closure_);
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
|
||||
|
||||
JSStructuredCloneWriter::~JSStructuredCloneWriter()
|
||||
{
|
||||
// Free any transferable data left lying around in the buffer
|
||||
if (out.count()) {
|
||||
out.discardTransferables(callbacks, closure);
|
||||
uint64_t* data;
|
||||
size_t size;
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!extractBuffer(&data, &size))
|
||||
oomUnsafe.crash("Unable to extract clone buffer");
|
||||
DiscardTransferables(data, size, callbacks, closure);
|
||||
js_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1410,10 +1306,10 @@ JSStructuredCloneWriter::transferOwnership()
|
|||
// Walk along the transferables and the transfer map at the same time,
|
||||
// grabbing out pointers from the transferables and stuffing them into the
|
||||
// transfer map.
|
||||
auto point = out.iter();
|
||||
MOZ_ASSERT(uint32_t(NativeEndian::swapFromLittleEndian(point.peek()) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
|
||||
uint64_t* point = out.rawBuffer();
|
||||
MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
|
||||
point++;
|
||||
MOZ_ASSERT(NativeEndian::swapFromLittleEndian(point.peek()) == transferableObjects.count());
|
||||
MOZ_ASSERT(LittleEndian::readUint64(point) == transferableObjects.count());
|
||||
point++;
|
||||
|
||||
RootedObject obj(context());
|
||||
|
@ -1426,7 +1322,7 @@ JSStructuredCloneWriter::transferOwnership()
|
|||
uint64_t extraData;
|
||||
|
||||
#if DEBUG
|
||||
SCInput::getPair(point.peek(), &tag, (uint32_t*) &ownership);
|
||||
SCInput::getPair(point, &tag, (uint32_t*) &ownership);
|
||||
MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_PENDING_ENTRY);
|
||||
MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED);
|
||||
#endif
|
||||
|
@ -1479,23 +1375,22 @@ JSStructuredCloneWriter::transferOwnership()
|
|||
MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY);
|
||||
}
|
||||
|
||||
point.write(NativeEndian::swapToLittleEndian(PairToUInt64(tag, ownership)));
|
||||
point.next();
|
||||
point.write(NativeEndian::swapToLittleEndian(reinterpret_cast<uint64_t>(content)));
|
||||
point.next();
|
||||
point.write(NativeEndian::swapToLittleEndian(extraData));
|
||||
point.next();
|
||||
LittleEndian::writeUint64(point++, PairToUInt64(tag, ownership));
|
||||
LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content));
|
||||
LittleEndian::writeUint64(point++, extraData);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(point <= out.rawBuffer() + out.count());
|
||||
#if DEBUG
|
||||
// Make sure there aren't any more transfer map entries after the expected
|
||||
// number we read out.
|
||||
if (!point.done()) {
|
||||
if (point < out.rawBuffer() + out.count()) {
|
||||
uint32_t tag, data;
|
||||
SCInput::getPair(point.peek(), &tag, &data);
|
||||
SCInput::getPair(point, &tag, &data);
|
||||
MOZ_ASSERT(tag < SCTAG_TRANSFER_MAP_HEADER || tag >= SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2005,7 +1900,7 @@ bool
|
|||
JSStructuredCloneReader::readTransferMap()
|
||||
{
|
||||
JSContext* cx = context();
|
||||
auto headerPos = in.tell();
|
||||
uint64_t* headerPos = in.tell();
|
||||
|
||||
uint32_t tag, data;
|
||||
if (!in.getPair(&tag, &data))
|
||||
|
@ -2020,7 +1915,7 @@ JSStructuredCloneReader::readTransferMap()
|
|||
return false;
|
||||
|
||||
for (uint64_t i = 0; i < numTransferables; i++) {
|
||||
auto pos = in.tell();
|
||||
uint64_t* pos = in.tell();
|
||||
|
||||
if (!in.readPair(&tag, &data))
|
||||
return false;
|
||||
|
@ -2076,20 +1971,21 @@ JSStructuredCloneReader::readTransferMap()
|
|||
|
||||
// Mark the SCTAG_TRANSFER_MAP_* entry as no longer owned by the input
|
||||
// buffer.
|
||||
pos.write(PairToUInt64(tag, JS::SCTAG_TMO_UNOWNED));
|
||||
MOZ_ASSERT(!pos.done());
|
||||
*pos = PairToUInt64(tag, JS::SCTAG_TMO_UNOWNED);
|
||||
MOZ_ASSERT(headerPos < pos && pos < in.end());
|
||||
|
||||
if (!allObjs.append(ObjectValue(*obj)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark the whole transfer map as consumed.
|
||||
MOZ_ASSERT(headerPos <= in.tell());
|
||||
#ifdef DEBUG
|
||||
SCInput::getPair(headerPos.peek(), &tag, &data);
|
||||
SCInput::getPair(headerPos, &tag, &data);
|
||||
MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_HEADER);
|
||||
MOZ_ASSERT(TransferableMapHeader(data) != SCTAG_TM_TRANSFERRED);
|
||||
#endif
|
||||
headerPos.write(PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED));
|
||||
*headerPos = PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2281,7 +2177,7 @@ JSStructuredCloneReader::read(MutableHandleValue vp)
|
|||
using namespace js;
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& buf,
|
||||
JS_ReadStructuredClone(JSContext* cx, uint64_t* buf, size_t nbytes,
|
||||
uint32_t version, MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* closure)
|
||||
|
@ -2294,11 +2190,11 @@ JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& buf,
|
|||
return false;
|
||||
}
|
||||
const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
|
||||
return ReadStructuredClone(cx, buf, vp, callbacks, closure);
|
||||
return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteStructuredClone(JSContext* cx, HandleValue value, JSStructuredCloneData* bufp,
|
||||
JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_t* nbytesp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* closure, HandleValue transferable)
|
||||
{
|
||||
|
@ -2307,14 +2203,26 @@ JS_WriteStructuredClone(JSContext* cx, HandleValue value, JSStructuredCloneData*
|
|||
assertSameCompartment(cx, value);
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks = optionalCallbacks;
|
||||
return WriteStructuredClone(cx, value, bufp, callbacks, closure, transferable);
|
||||
return WriteStructuredClone(cx, value, bufp, nbytesp, callbacks, closure, transferable);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(JSStructuredCloneData& data,
|
||||
JS_ClearStructuredClone(uint64_t* data, size_t nbytes,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* closure, bool freeData)
|
||||
{
|
||||
DiscardTransferables(data, nbytes, optionalCallbacks, closure);
|
||||
if (freeData) {
|
||||
js_free(data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes,
|
||||
bool* hasTransferable)
|
||||
{
|
||||
*hasTransferable = StructuredCloneHasTransferObjects(data);
|
||||
*hasTransferable = StructuredCloneHasTransferObjects(data, nbytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2359,8 +2267,8 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
|
|||
|
||||
JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
|
||||
{
|
||||
data_.ownTransferables_ = other.data_.ownTransferables_;
|
||||
other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
|
||||
ownTransferables_ = other.ownTransferables_;
|
||||
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
|
||||
}
|
||||
|
||||
JSAutoStructuredCloneBuffer&
|
||||
|
@ -2368,8 +2276,8 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
|
|||
{
|
||||
MOZ_ASSERT(&other != this);
|
||||
clear();
|
||||
data_.ownTransferables_ = other.data_.ownTransferables_;
|
||||
other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
|
||||
ownTransferables_ = other.ownTransferables_;
|
||||
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2377,68 +2285,81 @@ void
|
|||
JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* optionalClosure)
|
||||
{
|
||||
if (!data_.Size())
|
||||
if (!data_)
|
||||
return;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
optionalCallbacks ? optionalCallbacks : data_.callbacks_;
|
||||
void* closure = optionalClosure ? optionalClosure : data_.closure_;
|
||||
optionalCallbacks ? optionalCallbacks : callbacks_;
|
||||
void* closure = optionalClosure ? optionalClosure : closure_;
|
||||
|
||||
if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
|
||||
DiscardTransferables(data_, callbacks, closure);
|
||||
data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
|
||||
data_.Clear();
|
||||
if (ownTransferables_ == OwnsTransferablesIfAny)
|
||||
DiscardTransferables(data_, nbytes_, callbacks, closure);
|
||||
ownTransferables_ = NoTransferables;
|
||||
js_free(data_);
|
||||
data_ = nullptr;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t version,
|
||||
JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure)
|
||||
{
|
||||
// transferable objects cannot be copied
|
||||
if (StructuredCloneHasTransferObjects(srcData))
|
||||
if (StructuredCloneHasTransferObjects(data_, nbytes_))
|
||||
return false;
|
||||
|
||||
uint64_t* newData = static_cast<uint64_t*>(js_malloc(nbytes));
|
||||
if (!newData)
|
||||
return false;
|
||||
|
||||
js_memcpy(newData, srcData, nbytes);
|
||||
|
||||
clear();
|
||||
|
||||
auto iter = srcData.Iter();
|
||||
while (!iter.Done()) {
|
||||
data_.WriteBytes(iter.Data(), iter.RemainingInSegment());
|
||||
iter.Advance(srcData, iter.RemainingInSegment());
|
||||
}
|
||||
|
||||
data_ = newData;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = NoTransferables;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version,
|
||||
JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure)
|
||||
{
|
||||
clear();
|
||||
data_ = Move(data);
|
||||
data_ = data;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = OwnsTransferablesIfAny;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versionp,
|
||||
JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp,
|
||||
const JSStructuredCloneCallbacks** callbacks,
|
||||
void** closure)
|
||||
{
|
||||
*datap = data_;
|
||||
*nbytesp = nbytes_;
|
||||
if (versionp)
|
||||
*versionp = version_;
|
||||
if (callbacks)
|
||||
*callbacks = data_.callbacks_;
|
||||
*callbacks = callbacks_;
|
||||
if (closure)
|
||||
*closure = data_.closure_;
|
||||
*data = Move(data_);
|
||||
*closure = closure_;
|
||||
|
||||
data_ = nullptr;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
|
||||
callbacks_ = 0;
|
||||
closure_ = 0;
|
||||
ownTransferables_ = NoTransferables;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2447,7 +2368,8 @@ JSAutoStructuredCloneBuffer::read(JSContext* cx, MutableHandleValue vp,
|
|||
void* closure)
|
||||
{
|
||||
MOZ_ASSERT(cx);
|
||||
return !!JS_ReadStructuredClone(cx, data_, version_, vp,
|
||||
MOZ_ASSERT(data_);
|
||||
return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
|
||||
optionalCallbacks, closure);
|
||||
}
|
||||
|
||||
|
@ -2467,15 +2389,17 @@ JSAutoStructuredCloneBuffer::write(JSContext* cx, HandleValue value,
|
|||
void* closure)
|
||||
{
|
||||
clear();
|
||||
bool ok = JS_WriteStructuredClone(cx, value, &data_,
|
||||
bool ok = JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
|
||||
optionalCallbacks, closure,
|
||||
transferable);
|
||||
|
||||
if (ok) {
|
||||
data_.ownTransferables_ = OwnTransferablePolicy::OwnsTransferablesIfAny;
|
||||
ownTransferables_ = OwnsTransferablesIfAny;
|
||||
} else {
|
||||
data_ = nullptr;
|
||||
nbytes_ = 0;
|
||||
version_ = JS_STRUCTURED_CLONE_VERSION;
|
||||
data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
|
||||
ownTransferables_ = NoTransferables;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -135,6 +135,12 @@ nrappkit copyright:
|
|||
#endif
|
||||
#undef strlcpy
|
||||
|
||||
// TCPSocketChild.h doesn't include TypedArray.h
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ArrayBuffer;
|
||||
}
|
||||
}
|
||||
#include "mozilla/dom/network/TCPSocketChild.h"
|
||||
|
||||
#ifdef LOG_TEMP_INFO
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <algorithm>
|
||||
#include "mozilla/AllocPolicy.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
@ -52,9 +51,6 @@ class BufferList : private AllocPolicy
|
|||
char* End() const { return mData + mSize; }
|
||||
};
|
||||
|
||||
template<typename OtherAllocPolicy>
|
||||
friend class BufferList;
|
||||
|
||||
public:
|
||||
// For the convenience of callers, all segments are required to be a multiple
|
||||
// of 8 bytes in capacity. Also, every buffer except the last one is required
|
||||
|
@ -78,7 +74,6 @@ class BufferList : private AllocPolicy
|
|||
AllocPolicy aAP = AllocPolicy())
|
||||
: AllocPolicy(aAP),
|
||||
mOwning(true),
|
||||
mSegments(aAP),
|
||||
mSize(0),
|
||||
mStandardCapacity(aStandardCapacity)
|
||||
{
|
||||
|
@ -260,26 +255,7 @@ class BufferList : private AllocPolicy
|
|||
// AllocPolicy is only used for the buffer vector.
|
||||
template<typename BorrowingAllocPolicy>
|
||||
BufferList<BorrowingAllocPolicy> Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
|
||||
BorrowingAllocPolicy aAP = BorrowingAllocPolicy()) const;
|
||||
|
||||
// Return a new BufferList and move storage from this BufferList to it. The
|
||||
// new BufferList owns the buffers. Move can fail, in which case *aSuccess
|
||||
// will be false upon return. The new BufferList can use a different
|
||||
// AllocPolicy than the original one. The new OtherAllocPolicy is responsible
|
||||
// for freeing buffers, so the OtherAllocPolicy must use freeing method
|
||||
// compatible to the original one.
|
||||
template<typename OtherAllocPolicy>
|
||||
BufferList<OtherAllocPolicy> MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy());
|
||||
|
||||
// Return a new BufferList that adopts the byte range starting at Iter so that
|
||||
// range [aIter, aIter + aSize) is transplanted to the returned BufferList.
|
||||
// Contents of the buffer before aIter + aSize is left undefined.
|
||||
// Extract can fail, in which case *aSuccess will be false upon return. The
|
||||
// moved buffers are erased from the original BufferList. In case of extract
|
||||
// fails, the original BufferList is intact. All other iterators except aIter
|
||||
// are invalidated.
|
||||
// This method requires aIter and aSize to be 8-byte aligned.
|
||||
BufferList Extract(IterImpl& aIter, size_t aSize, bool* aSuccess);
|
||||
BorrowingAllocPolicy aAP = BorrowingAllocPolicy());
|
||||
|
||||
private:
|
||||
explicit BufferList(AllocPolicy aAP)
|
||||
|
@ -433,7 +409,7 @@ BufferList<AllocPolicy>::FlattenBytes(IterImpl& aIter, const char** aOutData, si
|
|||
template<typename AllocPolicy> template<typename BorrowingAllocPolicy>
|
||||
BufferList<BorrowingAllocPolicy>
|
||||
BufferList<AllocPolicy>::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
|
||||
BorrowingAllocPolicy aAP) const
|
||||
BorrowingAllocPolicy aAP)
|
||||
{
|
||||
BufferList<BorrowingAllocPolicy> result(aAP);
|
||||
|
||||
|
@ -441,7 +417,7 @@ BufferList<AllocPolicy>::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
|
|||
while (size) {
|
||||
size_t toAdvance = std::min(size, aIter.RemainingInSegment());
|
||||
|
||||
if (!toAdvance || !result.mSegments.append(typename BufferList<BorrowingAllocPolicy>::Segment(aIter.mData, toAdvance, toAdvance))) {
|
||||
if (!toAdvance || !result.mSegments.append(Segment(aIter.mData, toAdvance, toAdvance))) {
|
||||
*aSuccess = false;
|
||||
return result;
|
||||
}
|
||||
|
@ -454,98 +430,6 @@ BufferList<AllocPolicy>::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename AllocPolicy> template<typename OtherAllocPolicy>
|
||||
BufferList<OtherAllocPolicy>
|
||||
BufferList<AllocPolicy>::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP)
|
||||
{
|
||||
BufferList<OtherAllocPolicy> result(0, 0, mStandardCapacity, aAP);
|
||||
|
||||
IterImpl iter = Iter();
|
||||
while (!iter.Done()) {
|
||||
size_t toAdvance = iter.RemainingInSegment();
|
||||
|
||||
if (!toAdvance || !result.mSegments.append(typename BufferList<OtherAllocPolicy>::Segment(iter.mData, toAdvance, toAdvance))) {
|
||||
*aSuccess = false;
|
||||
return result;
|
||||
}
|
||||
iter.Advance(*this, toAdvance);
|
||||
}
|
||||
|
||||
result.mSize = mSize;
|
||||
mSegments.clear();
|
||||
mSize = 0;
|
||||
*aSuccess = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename AllocPolicy>
|
||||
BufferList<AllocPolicy>
|
||||
BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aSize);
|
||||
MOZ_RELEASE_ASSERT(mOwning);
|
||||
MOZ_ASSERT(aSize % kSegmentAlignment == 0);
|
||||
MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
|
||||
|
||||
IterImpl iter = aIter;
|
||||
size_t size = aSize;
|
||||
size_t toCopy = std::min(size, aIter.RemainingInSegment());
|
||||
MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
|
||||
|
||||
BufferList result(0, toCopy, mStandardCapacity);
|
||||
BufferList error(0, 0, mStandardCapacity);
|
||||
|
||||
// Copy the head
|
||||
if (!result.WriteBytes(aIter.mData, toCopy)) {
|
||||
*aSuccess = false;
|
||||
return error;
|
||||
}
|
||||
iter.Advance(*this, toCopy);
|
||||
size -= toCopy;
|
||||
|
||||
// Move segments to result
|
||||
auto resultGuard = MakeScopeExit([&] {
|
||||
*aSuccess = false;
|
||||
result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
|
||||
});
|
||||
|
||||
size_t movedSize = 0;
|
||||
uintptr_t toRemoveStart = iter.mSegment;
|
||||
uintptr_t toRemoveEnd = iter.mSegment;
|
||||
while (!iter.Done() &&
|
||||
!iter.HasRoomFor(size)) {
|
||||
if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
|
||||
mSegments[iter.mSegment].mSize,
|
||||
mSegments[iter.mSegment].mCapacity))) {
|
||||
return error;
|
||||
}
|
||||
movedSize += iter.RemainingInSegment();
|
||||
size -= iter.RemainingInSegment();
|
||||
toRemoveEnd++;
|
||||
iter.Advance(*this, iter.RemainingInSegment());
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if (!iter.HasRoomFor(size) ||
|
||||
!result.WriteBytes(iter.Data(), size)) {
|
||||
return error;
|
||||
}
|
||||
iter.Advance(*this, size);
|
||||
}
|
||||
|
||||
mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
|
||||
mSize -= movedSize;
|
||||
aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
|
||||
aIter.mData = iter.mData;
|
||||
aIter.mDataEnd = iter.mDataEnd;
|
||||
MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
|
||||
result.mSize = aSize;
|
||||
|
||||
resultGuard.release();
|
||||
*aSuccess = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_BufferList_h */
|
||||
|
|
|
@ -213,21 +213,6 @@ int main(void)
|
|||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
// MoveFallible
|
||||
|
||||
bool success;
|
||||
bl2 = bl.MoveFallible<InfallibleAllocPolicy>(&success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
MOZ_RELEASE_ASSERT(bl.Size() == 0);
|
||||
MOZ_RELEASE_ASSERT(bl.Iter().Done());
|
||||
MOZ_RELEASE_ASSERT(bl2.Size() == kSmallWrite * 3);
|
||||
|
||||
iter = bl2.Iter();
|
||||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kSmallWrite * 3));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
bl = bl2.MoveFallible<InfallibleAllocPolicy>(&success);
|
||||
|
||||
// Borrowing.
|
||||
|
||||
const size_t kBorrowStart = 4;
|
||||
|
@ -235,6 +220,7 @@ int main(void)
|
|||
|
||||
iter = bl.Iter();
|
||||
iter.Advance(bl, kBorrowStart);
|
||||
bool success;
|
||||
bl2 = bl.Borrow<InfallibleAllocPolicy>(iter, kBorrowSize, &success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
MOZ_RELEASE_ASSERT(bl2.Size() == kBorrowSize);
|
||||
|
@ -253,27 +239,5 @@ int main(void)
|
|||
MOZ_RELEASE_ASSERT(iter2.AdvanceAcrossSegments(bl2, kBorrowSize - 5));
|
||||
MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data());
|
||||
|
||||
// Extracting.
|
||||
|
||||
const size_t kExtractStart = 8;
|
||||
const size_t kExtractSize = 24;
|
||||
const size_t kExtractOverSize = 1000;
|
||||
|
||||
iter = bl.Iter();
|
||||
iter.Advance(bl, kExtractStart);
|
||||
bl2 = bl.Extract(iter, kExtractSize, &success);
|
||||
MOZ_RELEASE_ASSERT(success);
|
||||
MOZ_RELEASE_ASSERT(bl2.Size() == kExtractSize);
|
||||
|
||||
BufferList bl3 = bl.Extract(iter, kExtractOverSize, &success);
|
||||
MOZ_RELEASE_ASSERT(!success);
|
||||
|
||||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kExtractSize - kExtractStart));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
iter = bl2.Iter();
|
||||
MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kExtractSize));
|
||||
MOZ_RELEASE_ASSERT(iter.Done());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -43,33 +43,6 @@ namespace layers {
|
|||
struct TileClient;
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
struct SerializedStructuredCloneBuffer;
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace ipc {
|
||||
class StructuredCloneData;
|
||||
} // namespace ipc
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class ClonedMessageData;
|
||||
class MessagePortMessage;
|
||||
namespace indexedDB {
|
||||
struct StructuredCloneReadInfo;
|
||||
class SerializedStructuredCloneReadInfo;
|
||||
class ObjectStoreCursorResponse;
|
||||
} // namespace indexedDB
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class JSStructuredCloneData;
|
||||
|
||||
//
|
||||
// nsTArray is a resizable array class, like std::vector.
|
||||
//
|
||||
|
@ -703,30 +676,29 @@ struct MOZ_NEEDS_MEMMOVABLE_TYPE nsTArray_CopyChooser
|
|||
// Some classes require constructors/destructors to be called, so they are
|
||||
// specialized here.
|
||||
//
|
||||
#define DECLARE_USE_COPY_CONSTRUCTORS(T) \
|
||||
template<> \
|
||||
struct nsTArray_CopyChooser<T> \
|
||||
{ \
|
||||
typedef nsTArray_CopyWithConstructors<T> Type; \
|
||||
};
|
||||
|
||||
template<class E>
|
||||
struct nsTArray_CopyChooser<JS::Heap<E>>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<JS::Heap<E>> Type;
|
||||
};
|
||||
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(nsRegion)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(nsIntRegion)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::layers::TileClient)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::SerializedStructuredCloneBuffer)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::ipc::StructuredCloneData)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::ClonedMessageData)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::StructuredCloneReadInfo);
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::ObjectStoreCursorResponse)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo);
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(JSStructuredCloneData)
|
||||
DECLARE_USE_COPY_CONSTRUCTORS(mozilla::dom::MessagePortMessage)
|
||||
template<>
|
||||
struct nsTArray_CopyChooser<nsRegion>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<nsRegion> Type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct nsTArray_CopyChooser<nsIntRegion>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<nsIntRegion> Type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct nsTArray_CopyChooser<mozilla::layers::TileClient>
|
||||
{
|
||||
typedef nsTArray_CopyWithConstructors<mozilla::layers::TileClient> Type;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
|
|
Загрузка…
Ссылка в новой задаче