Bug 1609916 - Callback from SC to DOM on SAB cloning. r=luke

When structured clone reads a SAB and creates a new SAB object, or
when it serializes a SAB onto a channel, call a callback that lets the
embedder know.  The embedder can then adjust its policy.  Concretely,
we want to allow the browser to serialize threads in a process that
uses JS shared memory.

Note, for WebAssembly.Memory, reading and writing are delegated to the
cloning operations for SAB, so no special handling is needed.

Differential Revision: https://phabricator.services.mozilla.com/D61455

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lars T Hansen 2020-02-19 09:25:52 +00:00
parent 6b517ceeb5
commit 5dd2428621
4 changed files with 55 additions and 14 deletions

View File

@ -148,7 +148,7 @@ const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
StructuredCloneCallbacksRead, StructuredCloneCallbacksWrite,
StructuredCloneCallbacksError, StructuredCloneCallbacksReadTransfer,
StructuredCloneCallbacksWriteTransfer, StructuredCloneCallbacksFreeTransfer,
StructuredCloneCallbacksCanTransfer,
StructuredCloneCallbacksCanTransfer, nullptr,
};
// StructuredCloneHolderBase class

View File

@ -419,13 +419,10 @@ bool CopyingStructuredCloneWriteCallback(JSContext* aCx,
nsresult GetAddInfoCallback(JSContext* aCx, void* aClosure) {
static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
nullptr /* read */,
StructuredCloneWriteCallback /* write */,
nullptr /* reportError */,
nullptr /* readTransfer */,
nullptr /* writeTransfer */,
nullptr /* freeTransfer */,
nullptr /* canTransfer */
nullptr /* read */, StructuredCloneWriteCallback /* write */,
nullptr /* reportError */, nullptr /* readTransfer */,
nullptr /* writeTransfer */, nullptr /* freeTransfer */,
nullptr /* canTransfer */, nullptr /* sabCloned */
};
MOZ_ASSERT(aCx);
@ -1062,6 +1059,7 @@ bool IDBObjectStore::DeserializeValue(JSContext* aCx,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
// FIXME: Consider to use StructuredCloneHolder here and in other
@ -1219,6 +1217,7 @@ class DeserializeIndexValueHelper final : public Runnable {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
if (!JS_ReadStructuredClone(
@ -1325,6 +1324,7 @@ class DeserializeUpgradeValueHelper final : public Runnable {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
if (!JS_ReadStructuredClone(
@ -2571,7 +2571,8 @@ bool IDBObjectStore::ValueWrapper::Clone(JSContext* aCx) {
nullptr /* readTransfer */,
nullptr /* writeTransfer */,
nullptr /* freeTransfer */,
nullptr /* canTransfer */
nullptr /* canTransfer */,
nullptr /* sabCloned */
};
StructuredCloneInfo cloneInfo;

View File

@ -330,6 +330,19 @@ typedef bool (*CanTransferStructuredCloneOp)(JSContext* cx,
bool* sameProcessScopeRequired,
void* closure);
/**
* Called when a SharedArrayBuffer (including one owned by a Wasm memory object)
* has been processed in context `cx` by structured cloning. If `receiving` is
* true then the SAB has been received from a channel and a new SAB object has
* been created; if false then an existing SAB has been serialized onto a
* channel.
*
* If the callback returns false then the clone operation (read or write) will
* signal a failure.
*/
typedef bool (*SharedArrayBufferClonedOp)(JSContext* cx, bool receiving,
void* closure);
struct JSStructuredCloneCallbacks {
ReadStructuredCloneOp read;
WriteStructuredCloneOp write;
@ -338,6 +351,7 @@ struct JSStructuredCloneCallbacks {
TransferStructuredCloneOp writeTransfer;
FreeTransferStructuredCloneOp freeTransfer;
CanTransferStructuredCloneOp canTransfer;
SharedArrayBufferClonedOp sabCloned;
};
enum OwnTransferablePolicy {

View File

@ -470,6 +470,8 @@ struct JSStructuredCloneWriter {
const JSStructuredCloneCallbacks* cb,
void* cbClosure, const Value& tVal)
: out(cx, scope),
callbacks(cb),
closure(cbClosure),
objs(out.context()),
counts(out.context()),
objectEntries(out.context()),
@ -528,6 +530,13 @@ struct JSStructuredCloneWriter {
SCOutput out;
// The user defined callbacks that will be used to signal cloning, in some
// cases.
const JSStructuredCloneCallbacks* callbacks;
// Any value passed to the callbacks.
void* closure;
// Vector of objects with properties remaining to be written.
//
// NB: These can span multiple compartments, so the compartment must be
@ -1328,10 +1337,19 @@ bool JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj) {
intptr_t p = reinterpret_cast<intptr_t>(rawbuf);
uint32_t byteLength = sharedArrayBuffer->byteLength();
return out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT,
static_cast<uint32_t>(sizeof(p))) &&
out.writeBytes(&byteLength, sizeof(byteLength)) &&
out.writeBytes(&p, sizeof(p));
if (!(out.writePair(SCTAG_SHARED_ARRAY_BUFFER_OBJECT,
static_cast<uint32_t>(sizeof(p))) &&
out.writeBytes(&byteLength, sizeof(byteLength)) &&
out.writeBytes(&p, sizeof(p)))) {
return false;
}
if (callbacks && callbacks->sabCloned &&
!callbacks->sabCloned(context(), /*receiving=*/false, closure)) {
return false;
}
return true;
}
bool JSStructuredCloneWriter::writeSharedWasmMemory(HandleObject obj) {
@ -2307,12 +2325,20 @@ bool JSStructuredCloneReader::readSharedArrayBuffer(MutableHandleValue vp) {
return false;
}
JSObject* obj = SharedArrayBufferObject::New(context(), rawbuf, byteLength);
RootedObject obj(context(),
SharedArrayBufferObject::New(context(), rawbuf, byteLength));
if (!obj) {
rawbuf->dropReference();
return false;
}
// `rawbuf` is now owned by `obj`.
if (callbacks && callbacks->sabCloned &&
!callbacks->sabCloned(context(), /*receiving=*/true, closure)) {
return false;
}
vp.setObject(*obj);
return true;
}