Commit 3b15d950 authored by addaleax's avatar addaleax Committed by Commit bot

ValueSerializer: Add SetTreatArrayBufferViewsAsHostObjects() flag

Add `ValueSerializer::SetTreatArrayBufferViewsAsHostObjects()` which
instructs the `ValueSerializer` to treat ArrayBufferView objects as
host objects.

BUG=v8:5926

Review-Url: https://codereview.chromium.org/2696133007
Cr-Commit-Position: refs/heads/master@{#43281}
parent d91a7be5
...@@ -1799,6 +1799,15 @@ class V8_EXPORT ValueSerializer { ...@@ -1799,6 +1799,15 @@ class V8_EXPORT ValueSerializer {
uint32_t transfer_id, uint32_t transfer_id,
Local<SharedArrayBuffer> shared_array_buffer)); Local<SharedArrayBuffer> shared_array_buffer));
/*
* Indicate whether to treat ArrayBufferView objects as host objects,
* i.e. pass them to Delegate::WriteHostObject. This should not be
* called when no Delegate was passed.
*
* The default is not to treat ArrayBufferViews as host objects.
*/
void SetTreatArrayBufferViewsAsHostObjects(bool mode);
/* /*
* Write raw data in various common formats to the buffer. * Write raw data in various common formats to the buffer.
* Note that integer types are written in base-128 varint format, not with a * Note that integer types are written in base-128 varint format, not with a
......
...@@ -3158,6 +3158,10 @@ ValueSerializer::~ValueSerializer() { delete private_; } ...@@ -3158,6 +3158,10 @@ ValueSerializer::~ValueSerializer() { delete private_; }
void ValueSerializer::WriteHeader() { private_->serializer.WriteHeader(); } void ValueSerializer::WriteHeader() { private_->serializer.WriteHeader(); }
void ValueSerializer::SetTreatArrayBufferViewsAsHostObjects(bool mode) {
private_->serializer.SetTreatArrayBufferViewsAsHostObjects(mode);
}
Maybe<bool> ValueSerializer::WriteValue(Local<Context> context, Maybe<bool> ValueSerializer::WriteValue(Local<Context> context,
Local<Value> value) { Local<Value> value) {
PREPARE_FOR_EXECUTION_PRIMITIVE(context, ValueSerializer, WriteValue, bool); PREPARE_FOR_EXECUTION_PRIMITIVE(context, ValueSerializer, WriteValue, bool);
......
...@@ -170,6 +170,10 @@ void ValueSerializer::WriteHeader() { ...@@ -170,6 +170,10 @@ void ValueSerializer::WriteHeader() {
WriteVarint(kLatestVersion); WriteVarint(kLatestVersion);
} }
void ValueSerializer::SetTreatArrayBufferViewsAsHostObjects(bool mode) {
treat_array_buffer_views_as_host_objects_ = mode;
}
void ValueSerializer::WriteTag(SerializationTag tag) { void ValueSerializer::WriteTag(SerializationTag tag) {
uint8_t raw_tag = static_cast<uint8_t>(tag); uint8_t raw_tag = static_cast<uint8_t>(tag);
WriteRawBytes(&raw_tag, sizeof(raw_tag)); WriteRawBytes(&raw_tag, sizeof(raw_tag));
...@@ -318,7 +322,7 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { ...@@ -318,7 +322,7 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
// TODO(jbroman): It may be possible to avoid materializing a typed // TODO(jbroman): It may be possible to avoid materializing a typed
// array's buffer here. // array's buffer here.
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object); Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
if (!id_map_.Find(view)) { if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) {
Handle<JSArrayBuffer> buffer( Handle<JSArrayBuffer> buffer(
view->IsJSTypedArray() view->IsJSTypedArray()
? Handle<JSTypedArray>::cast(view)->GetBuffer() ? Handle<JSTypedArray>::cast(view)->GetBuffer()
...@@ -768,6 +772,9 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer( ...@@ -768,6 +772,9 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
} }
Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) { Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) {
if (treat_array_buffer_views_as_host_objects_) {
return WriteHostObject(handle(view, isolate_));
}
WriteTag(SerializationTag::kArrayBufferView); WriteTag(SerializationTag::kArrayBufferView);
ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array; ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array;
if (view->IsJSTypedArray()) { if (view->IsJSTypedArray()) {
......
...@@ -84,6 +84,15 @@ class ValueSerializer { ...@@ -84,6 +84,15 @@ class ValueSerializer {
void WriteRawBytes(const void* source, size_t length); void WriteRawBytes(const void* source, size_t length);
void WriteDouble(double value); void WriteDouble(double value);
/*
* Indicate whether to treat ArrayBufferView objects as host objects,
* i.e. pass them to Delegate::WriteHostObject. This should not be
* called when no Delegate was passed.
*
* The default is not to treat ArrayBufferViews as host objects.
*/
void SetTreatArrayBufferViewsAsHostObjects(bool mode);
private: private:
// Managing allocations of the internal buffer. // Managing allocations of the internal buffer.
Maybe<bool> ExpandBuffer(size_t required_capacity); Maybe<bool> ExpandBuffer(size_t required_capacity);
...@@ -138,6 +147,7 @@ class ValueSerializer { ...@@ -138,6 +147,7 @@ class ValueSerializer {
Isolate* const isolate_; Isolate* const isolate_;
v8::ValueSerializer::Delegate* const delegate_; v8::ValueSerializer::Delegate* const delegate_;
bool treat_array_buffer_views_as_host_objects_ = false;
uint8_t* buffer_ = nullptr; uint8_t* buffer_ = nullptr;
size_t buffer_size_ = 0; size_t buffer_size_ = 0;
size_t buffer_capacity_ = 0; size_t buffer_capacity_ = 0;
......
...@@ -263,6 +263,13 @@ class ValueSerializerTest : public TestWithIsolate { ...@@ -263,6 +263,13 @@ class ValueSerializerTest : public TestWithIsolate {
.ToLocalChecked(); .ToLocalChecked();
} }
Local<Object> NewDummyUint8Array() {
static uint8_t data[] = {4, 5, 6};
Local<ArrayBuffer> ab =
ArrayBuffer::New(isolate(), static_cast<void*>(data), sizeof(data));
return Uint8Array::New(ab, 0, sizeof(data));
}
private: private:
Local<Context> serialization_context_; Local<Context> serialization_context_;
Local<Context> deserialization_context_; Local<Context> deserialization_context_;
...@@ -2537,6 +2544,38 @@ TEST_F(ValueSerializerTestWithHostObject, RoundTripSameObject) { ...@@ -2537,6 +2544,38 @@ TEST_F(ValueSerializerTestWithHostObject, RoundTripSameObject) {
}); });
} }
class ValueSerializerTestWithHostArrayBufferView
: public ValueSerializerTestWithHostObject {
protected:
void BeforeEncode(ValueSerializer* serializer) override {
ValueSerializerTestWithHostObject::BeforeEncode(serializer);
serializer_->SetTreatArrayBufferViewsAsHostObjects(true);
}
};
TEST_F(ValueSerializerTestWithHostArrayBufferView, RoundTripUint8ArrayInput) {
EXPECT_CALL(serializer_delegate_, WriteHostObject(isolate(), _))
.WillOnce(Invoke([this](Isolate*, Local<Object> object) {
EXPECT_TRUE(object->IsUint8Array());
WriteExampleHostObjectTag();
return Just(true);
}));
EXPECT_CALL(deserializer_delegate_, ReadHostObject(isolate()))
.WillOnce(Invoke([this](Isolate*) {
EXPECT_TRUE(ReadExampleHostObjectTag());
return NewDummyUint8Array();
}));
RoundTripTest(
"({ a: new Uint8Array([1, 2, 3]), get b() { return this.a; }})",
[this](Local<Value> value) {
EXPECT_TRUE(
EvaluateScriptForResultBool("result.a instanceof Uint8Array"));
EXPECT_TRUE(
EvaluateScriptForResultBool("result.a.toString() === '4,5,6'"));
EXPECT_TRUE(EvaluateScriptForResultBool("result.a === result.b"));
});
}
// It's expected that WebAssembly has more exhaustive tests elsewhere; this // It's expected that WebAssembly has more exhaustive tests elsewhere; this
// mostly checks that the logic to embed it in structured clone serialization // mostly checks that the logic to embed it in structured clone serialization
// works correctly. // works correctly.
......
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