Commit 982c3164 authored by Malcolm White's avatar Malcolm White Committed by Commit Bot

De/serializes SharedArrayBuffers.

This is the v8 side of changes; blink changes are at https://chromium-review.googlesource.com/c/chromium/src/+/809228

BUG=chromium:716320

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Ia77764aed09dd609bf2304fe3c392a0e8ee16334
Reviewed-on: https://chromium-review.googlesource.com/847337Reviewed-by: 's avatarv8 autoroll <v8-autoroll@chromium.org>
Cr-Original-Commit-Position: refs/heads/6.5.123@{#1}
Cr-Original-Branched-From: 2a8e1e4a-refs/heads/master@{#50331}
Reviewed-on: https://chromium-review.googlesource.com/854395
Commit-Queue: Malcolm White <malcolmwhite@google.com>
Reviewed-by: 's avatarBen Smith <binji@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50699}
parent db1e370d
......@@ -1864,7 +1864,7 @@ class V8_EXPORT ValueSerializer {
* SharedArrayBuffer object. The embedder must return an ID for the
* object, using the same ID if this SharedArrayBuffer has already been
* serialized in this buffer. When deserializing, this ID will be passed to
* ValueDeserializer::TransferSharedArrayBuffer as |transfer_id|.
* ValueDeserializer::GetSharedArrayBufferFromId as |clone_id|.
*
* If the object cannot be serialized, an
* exception should be thrown and Nothing<uint32_t>() returned.
......@@ -1991,6 +1991,13 @@ class V8_EXPORT ValueDeserializer {
*/
virtual MaybeLocal<WasmCompiledModule> GetWasmModuleFromId(
Isolate* isolate, uint32_t transfer_id);
/**
* Get a SharedArrayBuffer given a clone_id previously provided
* by ValueSerializer::GetSharedArrayBufferId
*/
virtual MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
Isolate* isolate, uint32_t clone_id);
};
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size);
......
......@@ -3305,6 +3305,16 @@ MaybeLocal<WasmCompiledModule> ValueDeserializer::Delegate::GetWasmModuleFromId(
return MaybeLocal<WasmCompiledModule>();
}
MaybeLocal<SharedArrayBuffer>
ValueDeserializer::Delegate::GetSharedArrayBufferFromId(Isolate* v8_isolate,
uint32_t id) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->ScheduleThrow(*isolate->factory()->NewError(
isolate->error_function(),
i::MessageTemplate::kDataCloneDeserializationError));
return MaybeLocal<SharedArrayBuffer>();
}
struct ValueDeserializer::PrivateData {
PrivateData(i::Isolate* i, i::Vector<const uint8_t> data, Delegate* delegate)
: isolate(i), deserializer(i, data, delegate) {}
......
......@@ -3102,6 +3102,8 @@ class Serializer : public ValueSerializer::Delegate {
size_t index = shared_array_buffers_.size();
shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
data_->shared_array_buffer_contents_.push_back(
MaybeExternalize(shared_array_buffer));
return Just<uint32_t>(static_cast<uint32_t>(index));
}
......@@ -3174,13 +3176,6 @@ class Serializer : public ValueSerializer::Delegate {
data_->array_buffer_contents_.push_back(contents);
}
for (const auto& global_shared_array_buffer : shared_array_buffers_) {
Local<SharedArrayBuffer> shared_array_buffer =
Local<SharedArrayBuffer>::New(isolate_, global_shared_array_buffer);
data_->shared_array_buffer_contents_.push_back(
MaybeExternalize(shared_array_buffer));
}
return Just(true);
}
......@@ -3216,16 +3211,21 @@ class Deserializer : public ValueDeserializer::Delegate {
deserializer_.TransferArrayBuffer(index++, array_buffer);
}
index = 0;
for (const auto& contents : data_->shared_array_buffer_contents()) {
Local<SharedArrayBuffer> shared_array_buffer = SharedArrayBuffer::New(
isolate_, contents.Data(), contents.ByteLength());
deserializer_.TransferSharedArrayBuffer(index++, shared_array_buffer);
}
return deserializer_.ReadValue(context);
}
MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
Isolate* isolate, uint32_t clone_id) override {
DCHECK_NOT_NULL(data_);
if (clone_id < data_->shared_array_buffer_contents().size()) {
SharedArrayBuffer::Contents contents =
data_->shared_array_buffer_contents().at(clone_id);
return SharedArrayBuffer::New(isolate_, contents.Data(),
contents.ByteLength());
}
return MaybeLocal<SharedArrayBuffer>();
}
private:
Isolate* isolate_;
ValueDeserializer deserializer_;
......
......@@ -1182,15 +1182,16 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
return ReadJSMap();
case SerializationTag::kBeginJSSet:
return ReadJSSet();
case SerializationTag::kArrayBuffer:
return ReadJSArrayBuffer();
case SerializationTag::kArrayBufferTransfer: {
case SerializationTag::kArrayBuffer: {
const bool is_shared = false;
return ReadTransferredJSArrayBuffer(is_shared);
return ReadJSArrayBuffer(is_shared);
}
case SerializationTag::kArrayBufferTransfer: {
return ReadTransferredJSArrayBuffer();
}
case SerializationTag::kSharedArrayBuffer: {
const bool is_shared = true;
return ReadTransferredJSArrayBuffer(is_shared);
return ReadJSArrayBuffer(is_shared);
}
case SerializationTag::kWasmModule:
return ReadWasmModule();
......@@ -1572,8 +1573,25 @@ MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
return scope.CloseAndEscape(set);
}
MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer() {
MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer(
bool is_shared) {
uint32_t id = next_id_++;
if (is_shared) {
uint32_t clone_id;
Local<SharedArrayBuffer> sab_value;
if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
!delegate_
->GetSharedArrayBufferFromId(
reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
.ToLocal(&sab_value)) {
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSArrayBuffer);
return MaybeHandle<JSArrayBuffer>();
}
Handle<JSArrayBuffer> array_buffer = Utils::OpenHandle(*sab_value);
DCHECK_EQ(is_shared, array_buffer->is_shared());
AddObjectWithID(id, array_buffer);
return array_buffer;
}
uint32_t byte_length;
if (!ReadVarint<uint32_t>().To(&byte_length) ||
byte_length > static_cast<size_t>(end_ - position_)) {
......@@ -1592,8 +1610,7 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer() {
return array_buffer;
}
MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer(
bool is_shared) {
MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
uint32_t id = next_id_++;
uint32_t transfer_id;
Handle<NumberDictionary> transfer_map;
......@@ -1607,7 +1624,6 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer(
}
Handle<JSArrayBuffer> array_buffer(
JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_);
DCHECK_EQ(is_shared, array_buffer->is_shared());
AddObjectWithID(id, array_buffer);
return array_buffer;
}
......@@ -1744,7 +1760,7 @@ MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
const bool is_shared = true;
Handle<JSArrayBuffer> buffer;
if (!ReadTransferredJSArrayBuffer(is_shared).ToHandle(&buffer)) {
if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) {
return MaybeHandle<WasmMemoryObject>();
}
......
......@@ -266,8 +266,9 @@ class ValueDeserializer {
MaybeHandle<JSRegExp> ReadJSRegExp() WARN_UNUSED_RESULT;
MaybeHandle<JSMap> ReadJSMap() WARN_UNUSED_RESULT;
MaybeHandle<JSSet> ReadJSSet() WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBuffer> ReadJSArrayBuffer() WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBuffer> ReadTransferredJSArrayBuffer(bool is_shared)
MaybeHandle<JSArrayBuffer> ReadJSArrayBuffer(bool is_shared)
WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBuffer> ReadTransferredJSArrayBuffer()
WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView(
Handle<JSArrayBuffer> buffer) WARN_UNUSED_RESULT;
......
......@@ -28,17 +28,17 @@
// Flags: --harmony-sharedarraybuffer
if (this.Worker) {
(function TestTransfer() {
(function TestClone() {
var workerScript =
`onmessage = function(m) {
var sab = m;
var ta = new Uint32Array(sab);
if (sab.byteLength !== 16) {
throw new Error('SharedArrayBuffer transfer byteLength');
throw new Error('SharedArrayBuffer clone byteLength');
}
for (var i = 0; i < 4; ++i) {
if (ta[i] !== i) {
throw new Error('SharedArrayBuffer transfer value ' + i);
throw new Error('SharedArrayBuffer clone value ' + i);
}
}
// Atomically update ta[0]
......@@ -53,7 +53,7 @@ if (this.Worker) {
ta[i] = i;
}
// Transfer SharedArrayBuffer
// Clone SharedArrayBuffer
w.postMessage(sab);
assertEquals(16, sab.byteLength); // ArrayBuffer should not be neutered.
......@@ -68,7 +68,7 @@ if (this.Worker) {
assertEquals(16, sab.byteLength); // Still not neutered.
})();
(function TestTransferMulti() {
(function TestCloneMulti() {
var workerScript =
`onmessage = function(msg) {
var sab = msg.sab;
......
......@@ -2210,11 +2210,11 @@ TEST_F(ValueSerializerTest, DecodeInvalidDataView) {
{0xFF, 0x09, 0x42, 0x02, 0x00, 0x00, 0x56, 0x3F, 0x01, 0x03});
}
class ValueSerializerTestWithSharedArrayBufferTransfer
class ValueSerializerTestWithSharedArrayBufferClone
: public ValueSerializerTest {
protected:
ValueSerializerTestWithSharedArrayBufferTransfer()
: serializer_delegate_(this) {}
ValueSerializerTestWithSharedArrayBufferClone()
: serializer_delegate_(this), deserializer_delegate_(this) {}
void InitializeData(const std::vector<uint8_t>& data) {
data_ = data;
......@@ -2233,10 +2233,6 @@ class ValueSerializerTestWithSharedArrayBufferTransfer
const Local<SharedArrayBuffer>& input_buffer() { return input_buffer_; }
const Local<SharedArrayBuffer>& output_buffer() { return output_buffer_; }
void BeforeDecode(ValueDeserializer* deserializer) override {
deserializer->TransferSharedArrayBuffer(0, output_buffer_);
}
static void SetUpTestCase() {
flag_was_enabled_ = i::FLAG_harmony_sharedarraybuffer;
i::FLAG_harmony_sharedarraybuffer = true;
......@@ -2259,17 +2255,27 @@ class ValueSerializerTestWithSharedArrayBufferTransfer
class SerializerDelegate : public ValueSerializer::Delegate {
public:
explicit SerializerDelegate(
ValueSerializerTestWithSharedArrayBufferTransfer* test)
ValueSerializerTestWithSharedArrayBufferClone* test)
: test_(test) {}
MOCK_METHOD2(GetSharedArrayBufferId,
Maybe<uint32_t>(Isolate* isolate,
Local<SharedArrayBuffer> shared_array_buffer));
MOCK_METHOD2(GetSharedArrayBufferFromId,
MaybeLocal<SharedArrayBuffer>(Isolate* isolate, uint32_t id));
void ThrowDataCloneError(Local<String> message) override {
test_->isolate()->ThrowException(Exception::Error(message));
}
private:
ValueSerializerTestWithSharedArrayBufferTransfer* test_;
ValueSerializerTestWithSharedArrayBufferClone* test_;
};
class DeserializerDelegate : public ValueDeserializer::Delegate {
public:
explicit DeserializerDelegate(
ValueSerializerTestWithSharedArrayBufferClone* test) {}
MOCK_METHOD2(GetSharedArrayBufferFromId,
MaybeLocal<SharedArrayBuffer>(Isolate* isolate, uint32_t id));
};
#if __clang__
......@@ -2280,7 +2286,12 @@ class ValueSerializerTestWithSharedArrayBufferTransfer
return &serializer_delegate_;
}
ValueDeserializer::Delegate* GetDeserializerDelegate() override {
return &deserializer_delegate_;
}
SerializerDelegate serializer_delegate_;
DeserializerDelegate deserializer_delegate_;
private:
static bool flag_was_enabled_;
......@@ -2289,16 +2300,17 @@ class ValueSerializerTestWithSharedArrayBufferTransfer
Local<SharedArrayBuffer> output_buffer_;
};
bool ValueSerializerTestWithSharedArrayBufferTransfer::flag_was_enabled_ =
false;
bool ValueSerializerTestWithSharedArrayBufferClone::flag_was_enabled_ = false;
TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer,
RoundTripSharedArrayBufferTransfer) {
TEST_F(ValueSerializerTestWithSharedArrayBufferClone,
RoundTripSharedArrayBufferClone) {
InitializeData({0x00, 0x01, 0x80, 0xFF});
EXPECT_CALL(serializer_delegate_,
GetSharedArrayBufferId(isolate(), input_buffer()))
.WillRepeatedly(Return(Just(0U)));
EXPECT_CALL(deserializer_delegate_, GetSharedArrayBufferFromId(isolate(), 0U))
.WillRepeatedly(Return(output_buffer()));
RoundTripTest([this]() { return input_buffer(); },
[this](Local<Value> value) {
......@@ -2331,7 +2343,7 @@ TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer,
});
}
TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer,
TEST_F(ValueSerializerTestWithSharedArrayBufferClone,
RoundTripWebAssemblyMemory) {
bool flag_was_enabled = i::FLAG_experimental_wasm_threads;
i::FLAG_experimental_wasm_threads = true;
......@@ -2343,6 +2355,8 @@ TEST_F(ValueSerializerTestWithSharedArrayBufferTransfer,
EXPECT_CALL(serializer_delegate_,
GetSharedArrayBufferId(isolate(), input_buffer()))
.WillRepeatedly(Return(Just(0U)));
EXPECT_CALL(deserializer_delegate_, GetSharedArrayBufferFromId(isolate(), 0U))
.WillRepeatedly(Return(output_buffer()));
RoundTripTest(
[this]() -> Local<Value> {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment