Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(654)

Unified Diff: src/value-serializer.cc

Issue 2287653002: Blink-compatible serialization of array buffer views. (Closed)
Patch Set: Merge branch 'master' into vs-array-buffer-view Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/value-serializer.cc
diff --git a/src/value-serializer.cc b/src/value-serializer.cc
index bbfb2c77e038e5fe2051ec406e0ae66a15b9f045..8130856ed9e142ab72c37e92fc2871def7fba875 100644
--- a/src/value-serializer.cc
+++ b/src/value-serializer.cc
@@ -7,6 +7,7 @@
#include <type_traits>
#include "src/base/logging.h"
+#include "src/conversions.h"
#include "src/factory.h"
#include "src/handles-inl.h"
#include "src/isolate.h"
@@ -94,8 +95,33 @@ enum class SerializationTag : uint8_t {
kArrayBuffer = 'B',
// Array buffer (transferred). transferID:uint32_t
kArrayBufferTransfer = 't',
+ // View into an array buffer.
+ // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t
+ // For typed arrays, byteOffset and byteLength must be divisible by the size
+ // of the element.
+ // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an
+ // ObjectReference to one) serialized just before it. This is a quirk arising
+ // from the previous stack-based implementation.
+ kArrayBufferView = 'V',
};
+namespace {
+
+enum class ArrayBufferViewTag : uint8_t {
+ kInt8Array = 'b',
+ kUint8Array = 'B',
+ kUint8ClampedArray = 'C',
+ kInt16Array = 'w',
+ kUint16Array = 'W',
+ kInt32Array = 'd',
+ kUint32Array = 'D',
+ kFloat32Array = 'f',
+ kFloat64Array = 'F',
+ kDataView = '?',
+};
+
+} // namespace
+
ValueSerializer::ValueSerializer(Isolate* isolate)
: isolate_(isolate),
zone_(isolate->allocator()),
@@ -196,6 +222,23 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
case MUTABLE_HEAP_NUMBER_TYPE:
WriteHeapNumber(HeapNumber::cast(*object));
return Just(true);
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_DATA_VIEW_TYPE: {
+ // Despite being JSReceivers, these have their wrapped buffer serialized
+ // first. That makes this logic a little quirky, because it needs to
+ // happen before we assign object IDs.
+ // TODO(jbroman): It may be possible to avoid materializing a typed
+ // array's buffer here.
+ Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
+ if (!id_map_.Find(view)) {
+ Handle<JSArrayBuffer> buffer(
+ view->IsJSTypedArray()
+ ? Handle<JSTypedArray>::cast(view)->GetBuffer()
+ : handle(JSArrayBuffer::cast(view->buffer()), isolate_));
+ if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
+ }
+ return WriteJSReceiver(view);
+ }
default:
if (object->IsString()) {
WriteString(Handle<String>::cast(object));
@@ -319,6 +362,9 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
return WriteJSSet(Handle<JSSet>::cast(receiver));
case JS_ARRAY_BUFFER_TYPE:
return WriteJSArrayBuffer(JSArrayBuffer::cast(*receiver));
+ case JS_TYPED_ARRAY_TYPE:
+ case JS_DATA_VIEW_TYPE:
+ return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
default:
UNIMPLEMENTED();
break;
@@ -528,6 +574,28 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(JSArrayBuffer* array_buffer) {
return Just(true);
}
+Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) {
+ WriteTag(SerializationTag::kArrayBufferView);
+ ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array;
+ if (view->IsJSTypedArray()) {
+ switch (JSTypedArray::cast(view)->type()) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case kExternal##Type##Array: \
+ tag = ArrayBufferViewTag::k##Type##Array; \
+ break;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ }
+ } else {
+ DCHECK(view->IsJSDataView());
+ tag = ArrayBufferViewTag::kDataView;
+ }
+ WriteVarint(static_cast<uint8_t>(tag));
+ WriteVarint(NumberToUint32(view->byte_offset()));
+ WriteVarint(NumberToUint32(view->byte_length()));
+ return Just(true);
+}
+
Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
Handle<JSObject> object, Handle<FixedArray> keys) {
uint32_t properties_written = 0;
@@ -688,6 +756,22 @@ void ValueDeserializer::TransferArrayBuffer(
}
MaybeHandle<Object> ValueDeserializer::ReadObject() {
+ MaybeHandle<Object> result = ReadObjectInternal();
+
+ // ArrayBufferView is special in that it consumes the value before it, even
+ // after format version 0.
+ Handle<Object> object;
+ SerializationTag tag;
+ if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
+ PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
+ ConsumeTag(SerializationTag::kArrayBufferView);
+ result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
+ }
+
+ return result;
+}
+
+MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
SerializationTag tag;
if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
switch (tag) {
@@ -1054,6 +1138,46 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
return array_buffer;
}
+MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
+ Handle<JSArrayBuffer> buffer) {
+ uint32_t buffer_byte_length = NumberToUint32(buffer->byte_length());
+ uint8_t tag;
+ uint32_t byte_offset;
+ uint32_t byte_length;
+ if (!ReadVarint<uint8_t>().To(&tag) ||
+ !ReadVarint<uint32_t>().To(&byte_offset) ||
+ !ReadVarint<uint32_t>().To(&byte_length) ||
+ byte_offset > buffer_byte_length ||
+ byte_length > buffer_byte_length - byte_offset) {
+ return MaybeHandle<JSArrayBufferView>();
+ }
+ uint32_t id = next_id_++;
+ ExternalArrayType external_array_type = kExternalInt8Array;
+ unsigned element_size = 0;
+ switch (static_cast<ArrayBufferViewTag>(tag)) {
+ case ArrayBufferViewTag::kDataView: {
+ Handle<JSDataView> data_view =
+ isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
+ AddObjectWithID(id, data_view);
+ return data_view;
+ }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case ArrayBufferViewTag::k##Type##Array: \
+ external_array_type = kExternal##Type##Array; \
+ element_size = size; \
+ break;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ }
+ if (byte_offset % element_size != 0 || byte_length % element_size != 0) {
+ return MaybeHandle<JSArrayBufferView>();
+ }
+ Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
+ external_array_type, buffer, byte_offset, byte_length / element_size);
+ AddObjectWithID(id, typed_array);
+ return typed_array;
+}
+
Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
Handle<JSObject> object, SerializationTag end_tag) {
for (uint32_t num_properties = 0;; num_properties++) {
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698