Bug 1455071 - Bulk up SCOutput by changing it from storing a bare BufferList to a full JSStructuredCloneData, r=jorendorff

Then move JSStructuredCloneWriter's callbacks, callback data, and refsHeld into its SCOutput's JSStructuredCloneData. This removes the loose fields from JSStructuredCloneWriter and allows using move construction to remove a bunch of code.

--HG--
extra : rebase_source : 37cb0d4a15ffd0155bb7a55cd0fbefc358e649a8
This commit is contained in:
Steve Fink 2018-03-15 14:04:24 -07:00
Родитель f7f5c66182
Коммит d1d9f3cca9
2 изменённых файлов: 68 добавлений и 71 удалений

Просмотреть файл

@ -341,6 +341,11 @@ namespace js
}; };
} }
/**
* JSStructuredCloneData represents structured clone data together with the
* information needed to read/write/transfer/free the records within it, in the
* form of a set of callbacks.
*/
class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) : class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) :
public mozilla::BufferList<js::SystemAllocPolicy> public mozilla::BufferList<js::SystemAllocPolicy>
{ {
@ -356,14 +361,6 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) :
OwnTransferablePolicy ownTransferables_ = OwnTransferablePolicy::NoTransferables; OwnTransferablePolicy ownTransferables_ = OwnTransferablePolicy::NoTransferables;
js::SharedArrayRawBufferRefs refsHeld_; js::SharedArrayRawBufferRefs refsHeld_;
void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
void* closure,
OwnTransferablePolicy policy) {
callbacks_ = callbacks;
closure_ = closure;
ownTransferables_ = policy;
}
friend struct JSStructuredCloneWriter; friend struct JSStructuredCloneWriter;
friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer); friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
@ -382,7 +379,18 @@ public:
{} {}
JSStructuredCloneData(JSStructuredCloneData&& other) = default; JSStructuredCloneData(JSStructuredCloneData&& other) = default;
JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default; JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
~JSStructuredCloneData(); ~JSStructuredCloneData() { discardTransferables(); }
void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
void* closure,
OwnTransferablePolicy policy)
{
callbacks_ = callbacks;
closure_ = closure;
ownTransferables_ = policy;
}
void discardTransferables();
using BufferList::BufferList; using BufferList::BufferList;
}; };
@ -431,7 +439,7 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
const JSStructuredCloneCallbacks* callbacks, void* closure) const JSStructuredCloneCallbacks* callbacks, void* closure)
: scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION) : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
{ {
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
} }
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);

Просмотреть файл

@ -294,9 +294,17 @@ SharedArrayRawBufferRefs::releaseAll()
refs_.clear(); refs_.clear();
} }
// SCOutput provides an interface to write raw data -- eg uint64_ts, doubles,
// arrays of bytes -- into a structured clone data output stream. It also knows
// how to free any transferable data within that stream.
//
// Note that it contains a full JSStructuredCloneData object, which holds the
// callbacks necessary to read/write/transfer/free the data. For the purpose of
// this class, only the freeTransfer callback is relevant; the rest of the callbacks
// are used by the higher-level JSStructuredCloneWriter interface.
struct SCOutput { struct SCOutput {
public: public:
using Iter = BufferIterator<uint64_t, TempAllocPolicy>; using Iter = BufferIterator<uint64_t, SystemAllocPolicy>;
explicit SCOutput(JSContext* cx); explicit SCOutput(JSContext* cx);
@ -313,22 +321,27 @@ struct SCOutput {
template <class T> template <class T>
MOZ_MUST_USE bool writeArray(const T* p, size_t nbytes); MOZ_MUST_USE bool writeArray(const T* p, size_t nbytes);
MOZ_MUST_USE bool extractBuffer(JSStructuredCloneData* data); void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure); void* closure,
OwnTransferablePolicy policy)
{
buf.setCallbacks(callbacks, closure, policy);
}
void extractBuffer(JSStructuredCloneData* data) { *data = Move(buf); }
void discardTransferables();
uint64_t tell() const { return buf.Size(); } uint64_t tell() const { return buf.Size(); }
uint64_t count() const { return buf.Size() / sizeof(uint64_t); } uint64_t count() const { return buf.Size() / sizeof(uint64_t); }
Iter iter() { Iter iter() {
return BufferIterator<uint64_t, TempAllocPolicy>(buf); return Iter(buf);
} }
size_t offset(Iter dest) { size_t offset(Iter dest) {
return dest - iter(); return dest - iter();
} }
private:
JSContext* cx; JSContext* cx;
mozilla::BufferList<TempAllocPolicy> buf; JSStructuredCloneData buf;
}; };
class SCInput { class SCInput {
@ -461,11 +474,13 @@ struct JSStructuredCloneWriter {
const Value& tVal) const Value& tVal)
: out(cx), scope(scope), objs(out.context()), : out(cx), scope(scope), objs(out.context()),
counts(out.context()), entries(out.context()), counts(out.context()), entries(out.context()),
memory(out.context()), callbacks(cb), memory(out.context()),
closure(cbClosure), transferable(out.context(), tVal), transferable(out.context(), tVal),
transferableObjects(out.context(), GCHashSet<JSObject*>(cx)), transferableObjects(out.context(), GCHashSet<JSObject*>(cx)),
cloneDataPolicy(cloneDataPolicy) cloneDataPolicy(cloneDataPolicy)
{} {
out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables);
}
~JSStructuredCloneWriter(); ~JSStructuredCloneWriter();
@ -481,16 +496,8 @@ struct JSStructuredCloneWriter {
SCOutput& output() { return out; } SCOutput& output() { return out; }
bool extractBuffer(JSStructuredCloneData* data) { void extractBuffer(JSStructuredCloneData* newData) {
bool success = out.extractBuffer(data); out.extractBuffer(newData);
if (success) {
// Move the SharedArrayRawBuf references here, SCOutput::extractBuffer
// moves the serialized data.
data->refsHeld_.takeOwnership(Move(refsHeld));
data->setOptionalCallbacks(callbacks, closure,
OwnTransferablePolicy::OwnsTransferablesIfAny);
}
return success;
} }
JS::StructuredCloneScope cloneScope() const { return scope; } JS::StructuredCloneScope cloneScope() const { return scope; }
@ -554,21 +561,12 @@ struct JSStructuredCloneWriter {
SystemAllocPolicy>; SystemAllocPolicy>;
Rooted<CloneMemory> memory; Rooted<CloneMemory> memory;
// The user defined callbacks that will be used for cloning.
const JSStructuredCloneCallbacks* callbacks;
// Any value passed to JS_WriteStructuredClone.
void* closure;
// Set of transferable objects // Set of transferable objects
RootedValue transferable; RootedValue transferable;
Rooted<GCHashSet<JSObject*>> transferableObjects; Rooted<GCHashSet<JSObject*>> transferableObjects;
const JS::CloneDataPolicy cloneDataPolicy; const JS::CloneDataPolicy cloneDataPolicy;
// SharedArrayRawBuffers whose reference counts we have incremented.
SharedArrayRawBufferRefs refsHeld;
friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str); friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str);
friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v); friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v);
friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj); friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj);
@ -626,7 +624,12 @@ WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp,
const Value& transferable) const Value& transferable)
{ {
JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable); JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable);
return w.init() && w.write(v) && w.extractBuffer(bufp); if (!w.init())
return false;
if (!w.write(v))
return false;
w.extractBuffer(bufp);
return true;
} }
bool bool
@ -906,7 +909,6 @@ SCInput::readPtr(void** p)
SCOutput::SCOutput(JSContext* cx) SCOutput::SCOutput(JSContext* cx)
: cx(cx) : cx(cx)
, buf(0, 0, 4096, cx)
{ {
} }
@ -1014,29 +1016,17 @@ SCOutput::writePtr(const void* p)
return write(reinterpret_cast<uint64_t>(p)); return write(reinterpret_cast<uint64_t>(p));
} }
bool
SCOutput::extractBuffer(JSStructuredCloneData* data)
{
bool success;
mozilla::BufferList<SystemAllocPolicy> out =
buf.MoveFallible<SystemAllocPolicy>(&success);
if (!success) {
ReportOutOfMemory(cx);
return false;
}
*data = JSStructuredCloneData(Move(out));
return true;
}
void void
SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure) SCOutput::discardTransferables()
{ {
DiscardTransferables(buf, cb, cbClosure); buf.discardTransferables();
} }
} // namespace js } // namespace js
JSStructuredCloneData::~JSStructuredCloneData()
void
JSStructuredCloneData::discardTransferables()
{ {
if (!Size()) if (!Size())
return; return;
@ -1049,9 +1039,8 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
JSStructuredCloneWriter::~JSStructuredCloneWriter() JSStructuredCloneWriter::~JSStructuredCloneWriter()
{ {
// Free any transferable data left lying around in the buffer // Free any transferable data left lying around in the buffer
if (out.count()) { if (out.count())
out.discardTransferables(callbacks, closure); out.discardTransferables();
}
} }
bool bool
@ -1129,11 +1118,11 @@ JSStructuredCloneWriter::parseTransferable()
} }
else { else {
if (!callbacks || !callbacks->canTransfer) if (!out.buf.callbacks_ || !out.buf.callbacks_->canTransfer)
return reportDataCloneError(JS_SCERR_TRANSFERABLE); return reportDataCloneError(JS_SCERR_TRANSFERABLE);
JSAutoCompartment ac(cx, unwrappedObj); JSAutoCompartment ac(cx, unwrappedObj);
if (!callbacks->canTransfer(cx, unwrappedObj, closure)) if (!out.buf.callbacks_->canTransfer(cx, unwrappedObj, out.buf.closure_))
return false; return false;
} }
@ -1152,7 +1141,7 @@ JSStructuredCloneWriter::parseTransferable()
bool bool
JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId) JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId)
{ {
ReportDataCloneError(context(), callbacks, errorId); ReportDataCloneError(context(), out.buf.callbacks_, errorId);
return false; return false;
} }
@ -1285,7 +1274,7 @@ JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>()); Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject(); SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
if (!refsHeld.acquire(context(), rawbuf)) if (!out.buf.refsHeld_.acquire(context(), rawbuf))
return false; return false;
// We must serialize the length so that the buffer object arrives in the // We must serialize the length so that the buffer object arrives in the
@ -1611,8 +1600,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
return traverseSavedFrame(obj); return traverseSavedFrame(obj);
} }
if (callbacks && callbacks->write) if (out.buf.callbacks_ && out.buf.callbacks_->write)
return callbacks->write(context(), this, obj, closure); return out.buf.callbacks_->write(context(), this, obj, out.buf.closure_);
// else fall through // else fall through
} }
@ -1755,9 +1744,9 @@ JSStructuredCloneWriter::transferOwnership()
extraData = nbytes; extraData = nbytes;
} }
} else { } else {
if (!callbacks || !callbacks->writeTransfer) if (!out.buf.callbacks_ || !out.buf.callbacks_->writeTransfer)
return reportDataCloneError(JS_SCERR_TRANSFERABLE); return reportDataCloneError(JS_SCERR_TRANSFERABLE);
if (!callbacks->writeTransfer(cx, obj, closure, &tag, &ownership, &content, &extraData)) if (!out.buf.callbacks_->writeTransfer(cx, obj, out.buf.closure_, &tag, &ownership, &content, &extraData))
return false; return false;
MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY); MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY);
} }
@ -2872,7 +2861,7 @@ JSAutoStructuredCloneBuffer::copy(JSContext* cx, const JSStructuredCloneData& sr
if (!data_.refsHeld_.acquireAll(cx, srcData.refsHeld_)) if (!data_.refsHeld_.acquireAll(cx, srcData.refsHeld_))
return false; return false;
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
return true; return true;
} }
@ -2884,7 +2873,7 @@ JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t versio
clear(); clear();
data_ = Move(data); data_ = Move(data);
version_ = version; version_ = version;
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny); data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
} }
void void
@ -2901,7 +2890,7 @@ JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versio
*data = Move(data_); *data = Move(data_);
version_ = 0; version_ = 0;
data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables); data_.setCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
} }
bool bool