Skip to content

Commit

Permalink
Bug 1264642 - Part 4. Use BufferList to replace raw buffers in Struct…
Browse files Browse the repository at this point in the history
…uredClone. r=baku r=billm r=jorendorff

In JS StructuredClone BufferList<SystemAllocPolicy> is typedef'd to
JSStructuredCloneData and use everywhere in gecko that stores structured
clone data.

This patch changed some raw pointers to UniquePtr<JSStructuredCloneData>
and some to stack allocated JSStructuredCloneData for better life time
management. Some parameters or methods are deleted because of changing
to the new data structure.

MessagePortMessage now has the exactly same structure with
ClonedMessageData. Maybe in the future they can be consolidated.

MozReview-Commit-ID: 1IY9p5eKLgv
  • Loading branch information
kanru committed Aug 22, 2016
1 parent f874364 commit f453960
Show file tree
Hide file tree
Showing 20 changed files with 588 additions and 537 deletions.
59 changes: 11 additions & 48 deletions dom/base/StructuredCloneHolder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ StructuredCloneCallbacksError(JSContext* aCx,
NS_WARNING("Failed to clone data.");
}

const JSStructuredCloneCallbacks gCallbacks = {
} // anonymous namespace

const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
StructuredCloneCallbacksRead,
StructuredCloneCallbacksWrite,
StructuredCloneCallbacksError,
Expand All @@ -142,8 +144,6 @@ const JSStructuredCloneCallbacks gCallbacks = {
StructuredCloneCallbacksFreeTransfer
};

} // anonymous namespace

// StructuredCloneHolderBase class

StructuredCloneHolderBase::StructuredCloneHolderBase(StructuredCloneScope aScope)
Expand Down Expand Up @@ -185,9 +185,9 @@ StructuredCloneHolderBase::Write(JSContext* aCx,
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");

mBuffer = new JSAutoStructuredCloneBuffer(mStructuredCloneScope, &gCallbacks, this);
mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope, &StructuredCloneHolder::sCallbacks, this);

if (!mBuffer->write(aCx, aValue, aTransfer, &gCallbacks, this)) {
if (!mBuffer->write(aCx, aValue, aTransfer, &StructuredCloneHolder::sCallbacks, this)) {
mBuffer = nullptr;
return false;
}
Expand All @@ -202,7 +202,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, &gCallbacks, this);
bool ok = mBuffer->read(aCx, aValue, &StructuredCloneHolder::sCallbacks, this);
return ok;
}

Expand Down Expand Up @@ -311,20 +311,18 @@ StructuredCloneHolder::Read(nsISupports* aParent,
void
StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
JSStructuredCloneData& aBuffer,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
{
ReadFromBuffer(aParent, aCx, aBuffer, aBufferLength,
ReadFromBuffer(aParent, aCx, aBuffer,
JS_STRUCTURED_CLONE_VERSION, aValue, aRv);
}

void
StructuredCloneHolder::ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
JSStructuredCloneData& aBuffer,
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
Expand All @@ -333,53 +331,18 @@ 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, aBufferLength, aAlgorithmVersion,
mStructuredCloneScope, aValue, &gCallbacks,
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion,
mStructuredCloneScope, aValue, &sCallbacks,
this)) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
}

void
StructuredCloneHolder::MoveBufferDataToArray(FallibleTArray<uint8_t>& aArray,
ErrorResult& aRv)
{
MOZ_ASSERT_IF(mStructuredCloneScope == StructuredCloneScope::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,
Expand Down
30 changes: 7 additions & 23 deletions dom/base/StructuredCloneHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "js/StructuredClone.h"
#include "mozilla/Move.h"
#include "nsAutoPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsISupports.h"
#include "nsTArray.h"

Expand Down Expand Up @@ -102,20 +102,14 @@ class StructuredCloneHolderBase
return !!mBuffer;
}

uint64_t* BufferData() const
JSStructuredCloneData& BufferData() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
return mBuffer->data();
}

size_t BufferSize() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
return mBuffer->nbytes();
}

protected:
nsAutoPtr<JSAutoStructuredCloneBuffer> mBuffer;
UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;

StructuredCloneScope mStructuredCloneScope;

Expand Down Expand Up @@ -172,12 +166,6 @@ class StructuredCloneHolder : public StructuredCloneHolderBase
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
{
Expand Down Expand Up @@ -266,29 +254,25 @@ class StructuredCloneHolder : public StructuredCloneHolderBase
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,
uint64_t* aBuffer,
size_t aBufferLength,
JSStructuredCloneData& aBuffer,
JS::MutableHandle<JS::Value> aValue,
ErrorResult &aRv);

void ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
JSStructuredCloneData& aBuffer,
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;

Expand Down
11 changes: 8 additions & 3 deletions dom/base/nsFrameMessageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,13 @@ BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType*
ClonedMessageData& aClonedData)
{
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
buffer.data = aData.Data();
buffer.dataLength = aData.DataLength();
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;
}
aClonedData.identfiers().AppendElements(aData.PortIdentifiers());

const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
Expand Down Expand Up @@ -325,7 +330,7 @@ UnpackClonedMessageData(const ClonedMessageData& aClonedData,
const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();

aData.UseExternalData(buffer.data, buffer.dataLength);
aData.UseExternalData(buffer.data);

aData.PortIdentifiers().AppendElements(identifiers);

Expand Down
6 changes: 5 additions & 1 deletion dom/base/nsStructuredCloneContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
return NS_ERROR_FAILURE;
}

nsAutoCString binaryData(reinterpret_cast<char*>(Data()), DataLength());
auto iter = Data().Iter();
size_t size = Data().Size();
nsAutoCString binaryData;
binaryData.SetLength(size);
Data().ReadBytes(iter, binaryData.BeginWriting(), size);
nsAutoCString base64Data;
nsresult rv = Base64Encode(binaryData, base64Data);
if (NS_WARN_IF(NS_FAILED(rv))) {
Expand Down
8 changes: 6 additions & 2 deletions dom/broadcastchannel/BroadcastChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,13 @@ class BCPostMessageRunnable final : public nsIRunnable,

ClonedMessageData message;

bool success;
SerializedStructuredCloneBuffer& buffer = message.data();
buffer.data = mData->BufferData();
buffer.dataLength = mData->BufferSize();
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;
}

PBackgroundChild* backgroundManager = mActor->Manager();
MOZ_ASSERT(backgroundManager);
Expand Down
5 changes: 2 additions & 3 deletions dom/broadcastchannel/BroadcastChannelChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,11 @@ 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.dataLength) {
if (buffer.data.Size()) {
ErrorResult rv;
cloneData.UseExternalData(buffer.data);
cloneData.Read(cx, &value, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
Expand Down
Loading

0 comments on commit f453960

Please sign in to comment.