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

Side by Side Diff: src/value-serializer.cc

Issue 2471923002: Support structured clone of compiled WebAssembly modules. (Closed)
Patch Set: override FLAG_expose_wasm earlier in the test Created 4 years, 1 month 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 unified diff | Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/value-serializer.h" 5 #include "src/value-serializer.h"
6 6
7 #include <type_traits> 7 #include <type_traits>
8 8
9 #include "src/base/logging.h" 9 #include "src/base/logging.h"
10 #include "src/conversions.h" 10 #include "src/conversions.h"
11 #include "src/factory.h" 11 #include "src/factory.h"
12 #include "src/flags.h"
12 #include "src/handles-inl.h" 13 #include "src/handles-inl.h"
13 #include "src/isolate.h" 14 #include "src/isolate.h"
14 #include "src/objects-inl.h" 15 #include "src/objects-inl.h"
15 #include "src/objects.h" 16 #include "src/objects.h"
17 #include "src/snapshot/code-serializer.h"
16 #include "src/transitions.h" 18 #include "src/transitions.h"
19 #include "src/wasm/wasm-module.h"
20 #include "src/wasm/wasm-result.h"
17 21
18 namespace v8 { 22 namespace v8 {
19 namespace internal { 23 namespace internal {
20 24
21 static const uint32_t kLatestVersion = 9; 25 static const uint32_t kLatestVersion = 9;
22 static const int kPretenureThreshold = 100 * KB; 26 static const int kPretenureThreshold = 100 * KB;
23 27
24 template <typename T> 28 template <typename T>
25 static size_t BytesNeededForVarint(T value) { 29 static size_t BytesNeededForVarint(T value) {
26 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 30 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 // View into an array buffer. 104 // View into an array buffer.
101 // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t 105 // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t
102 // For typed arrays, byteOffset and byteLength must be divisible by the size 106 // For typed arrays, byteOffset and byteLength must be divisible by the size
103 // of the element. 107 // of the element.
104 // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an 108 // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an
105 // ObjectReference to one) serialized just before it. This is a quirk arising 109 // ObjectReference to one) serialized just before it. This is a quirk arising
106 // from the previous stack-based implementation. 110 // from the previous stack-based implementation.
107 kArrayBufferView = 'V', 111 kArrayBufferView = 'V',
108 // Shared array buffer (transferred). transferID:uint32_t 112 // Shared array buffer (transferred). transferID:uint32_t
109 kSharedArrayBufferTransfer = 'u', 113 kSharedArrayBufferTransfer = 'u',
114 // Compiled WebAssembly module. encodingType:(one-byte tag).
115 // If encodingType == 'y' (raw bytes):
116 // wasmWireByteLength:uint32_t, then raw data
117 // compiledDataLength:uint32_t, then raw data
118 kWasmModule = 'W',
110 }; 119 };
111 120
112 namespace { 121 namespace {
113 122
114 enum class ArrayBufferViewTag : uint8_t { 123 enum class ArrayBufferViewTag : uint8_t {
115 kInt8Array = 'b', 124 kInt8Array = 'b',
116 kUint8Array = 'B', 125 kUint8Array = 'B',
117 kUint8ClampedArray = 'C', 126 kUint8ClampedArray = 'C',
118 kInt16Array = 'w', 127 kInt16Array = 'w',
119 kUint16Array = 'W', 128 kUint16Array = 'W',
120 kInt32Array = 'd', 129 kInt32Array = 'd',
121 kUint32Array = 'D', 130 kUint32Array = 'D',
122 kFloat32Array = 'f', 131 kFloat32Array = 'f',
123 kFloat64Array = 'F', 132 kFloat64Array = 'F',
124 kDataView = '?', 133 kDataView = '?',
125 }; 134 };
126 135
136 enum class WasmEncodingTag : uint8_t {
137 kRawBytes = 'y',
138 };
139
127 } // namespace 140 } // namespace
128 141
129 ValueSerializer::ValueSerializer(Isolate* isolate, 142 ValueSerializer::ValueSerializer(Isolate* isolate,
130 v8::ValueSerializer::Delegate* delegate) 143 v8::ValueSerializer::Delegate* delegate)
131 : isolate_(isolate), 144 : isolate_(isolate),
132 delegate_(delegate), 145 delegate_(delegate),
133 zone_(isolate->allocator(), ZONE_NAME), 146 zone_(isolate->allocator(), ZONE_NAME),
134 id_map_(isolate->heap(), &zone_), 147 id_map_(isolate->heap(), &zone_),
135 array_buffer_transfer_map_(isolate->heap(), &zone_) {} 148 array_buffer_transfer_map_(isolate->heap(), &zone_) {}
136 149
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 // If we are at the end of the stack, abort. This function may recurse. 371 // If we are at the end of the stack, abort. This function may recurse.
359 STACK_CHECK(isolate_, Nothing<bool>()); 372 STACK_CHECK(isolate_, Nothing<bool>());
360 373
361 HandleScope scope(isolate_); 374 HandleScope scope(isolate_);
362 switch (instance_type) { 375 switch (instance_type) {
363 case JS_ARRAY_TYPE: 376 case JS_ARRAY_TYPE:
364 return WriteJSArray(Handle<JSArray>::cast(receiver)); 377 return WriteJSArray(Handle<JSArray>::cast(receiver));
365 case JS_OBJECT_TYPE: 378 case JS_OBJECT_TYPE:
366 case JS_API_OBJECT_TYPE: { 379 case JS_API_OBJECT_TYPE: {
367 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver); 380 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
368 return js_object->GetInternalFieldCount() ? WriteHostObject(js_object) 381 Map* map = js_object->map();
369 : WriteJSObject(js_object); 382 if (FLAG_expose_wasm &&
383 map->GetConstructor() ==
384 isolate_->native_context()->wasm_module_constructor()) {
385 return WriteWasmModule(js_object);
386 } else if (JSObject::GetInternalFieldCount(map)) {
387 return WriteHostObject(js_object);
388 } else {
389 return WriteJSObject(js_object);
390 }
370 } 391 }
371 case JS_SPECIAL_API_OBJECT_TYPE: 392 case JS_SPECIAL_API_OBJECT_TYPE:
372 return WriteHostObject(Handle<JSObject>::cast(receiver)); 393 return WriteHostObject(Handle<JSObject>::cast(receiver));
373 case JS_DATE_TYPE: 394 case JS_DATE_TYPE:
374 WriteJSDate(JSDate::cast(*receiver)); 395 WriteJSDate(JSDate::cast(*receiver));
375 return Just(true); 396 return Just(true);
376 case JS_VALUE_TYPE: 397 case JS_VALUE_TYPE:
377 return WriteJSValue(Handle<JSValue>::cast(receiver)); 398 return WriteJSValue(Handle<JSValue>::cast(receiver));
378 case JS_REGEXP_TYPE: 399 case JS_REGEXP_TYPE:
379 WriteJSRegExp(JSRegExp::cast(*receiver)); 400 WriteJSRegExp(JSRegExp::cast(*receiver));
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 } else { 731 } else {
711 DCHECK(view->IsJSDataView()); 732 DCHECK(view->IsJSDataView());
712 tag = ArrayBufferViewTag::kDataView; 733 tag = ArrayBufferViewTag::kDataView;
713 } 734 }
714 WriteVarint(static_cast<uint8_t>(tag)); 735 WriteVarint(static_cast<uint8_t>(tag));
715 WriteVarint(NumberToUint32(view->byte_offset())); 736 WriteVarint(NumberToUint32(view->byte_offset()));
716 WriteVarint(NumberToUint32(view->byte_length())); 737 WriteVarint(NumberToUint32(view->byte_length()));
717 return Just(true); 738 return Just(true);
718 } 739 }
719 740
741 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) {
742 Handle<wasm::WasmCompiledModule> compiled_part(
743 wasm::WasmCompiledModule::cast(object->GetInternalField(0)), isolate_);
744 WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes;
745 WriteTag(SerializationTag::kWasmModule);
746 WriteRawBytes(&encoding_tag, sizeof(encoding_tag));
747
748 Handle<String> wire_bytes = compiled_part->module_bytes();
749 int wire_bytes_length = wire_bytes->length();
750 WriteVarint<uint32_t>(wire_bytes_length);
751 uint8_t* destination = ReserveRawBytes(wire_bytes_length);
752 String::WriteToFlat(*wire_bytes, destination, 0, wire_bytes_length);
753
754 std::unique_ptr<ScriptData> script_data =
755 WasmCompiledModuleSerializer::SerializeWasmModule(isolate_,
756 compiled_part);
757 int script_data_length = script_data->length();
758 WriteVarint<uint32_t>(script_data_length);
759 WriteRawBytes(script_data->data(), script_data_length);
760
761 return Just(true);
762 }
763
720 Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) { 764 Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) {
721 if (!delegate_) { 765 if (!delegate_) {
722 isolate_->Throw(*isolate_->factory()->NewError( 766 isolate_->Throw(*isolate_->factory()->NewError(
723 isolate_->error_function(), MessageTemplate::kDataCloneError, object)); 767 isolate_->error_function(), MessageTemplate::kDataCloneError, object));
724 return Nothing<bool>(); 768 return Nothing<bool>();
725 } 769 }
726 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 770 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
727 Maybe<bool> result = 771 Maybe<bool> result =
728 delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object)); 772 delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
729 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); 773 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 case SerializationTag::kArrayBuffer: 1064 case SerializationTag::kArrayBuffer:
1021 return ReadJSArrayBuffer(); 1065 return ReadJSArrayBuffer();
1022 case SerializationTag::kArrayBufferTransfer: { 1066 case SerializationTag::kArrayBufferTransfer: {
1023 const bool is_shared = false; 1067 const bool is_shared = false;
1024 return ReadTransferredJSArrayBuffer(is_shared); 1068 return ReadTransferredJSArrayBuffer(is_shared);
1025 } 1069 }
1026 case SerializationTag::kSharedArrayBufferTransfer: { 1070 case SerializationTag::kSharedArrayBufferTransfer: {
1027 const bool is_shared = true; 1071 const bool is_shared = true;
1028 return ReadTransferredJSArrayBuffer(is_shared); 1072 return ReadTransferredJSArrayBuffer(is_shared);
1029 } 1073 }
1074 case SerializationTag::kWasmModule:
1075 return ReadWasmModule();
1030 default: 1076 default:
1031 // TODO(jbroman): Introduce an explicit tag for host objects to avoid 1077 // TODO(jbroman): Introduce an explicit tag for host objects to avoid
1032 // having to treat every unknown tag as a potential host object. 1078 // having to treat every unknown tag as a potential host object.
1033 position_--; 1079 position_--;
1034 return ReadHostObject(); 1080 return ReadHostObject();
1035 } 1081 }
1036 } 1082 }
1037 1083
1038 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { 1084 MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
1039 uint32_t utf8_length; 1085 uint32_t utf8_length;
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
1422 byte_length % element_size != 0) { 1468 byte_length % element_size != 0) {
1423 return MaybeHandle<JSArrayBufferView>(); 1469 return MaybeHandle<JSArrayBufferView>();
1424 } 1470 }
1425 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( 1471 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
1426 external_array_type, buffer, byte_offset, byte_length / element_size, 1472 external_array_type, buffer, byte_offset, byte_length / element_size,
1427 pretenure_); 1473 pretenure_);
1428 AddObjectWithID(id, typed_array); 1474 AddObjectWithID(id, typed_array);
1429 return typed_array; 1475 return typed_array;
1430 } 1476 }
1431 1477
1478 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
1479 if (!FLAG_expose_wasm) return MaybeHandle<JSObject>();
1480
1481 Vector<const uint8_t> encoding_tag;
1482 if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) ||
1483 encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) {
1484 return MaybeHandle<JSObject>();
1485 }
1486
1487 // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled
1488 // script data.
1489 static_assert(sizeof(int) <= sizeof(uint32_t),
1490 "max int must fit in uint32_t");
1491 const uint32_t max_valid_size = std::numeric_limits<int>::max();
1492 uint32_t wire_bytes_length = 0;
1493 Vector<const uint8_t> wire_bytes;
1494 uint32_t compiled_bytes_length = 0;
1495 Vector<const uint8_t> compiled_bytes;
1496 if (!ReadVarint<uint32_t>().To(&wire_bytes_length) ||
1497 wire_bytes_length > max_valid_size ||
1498 !ReadRawBytes(wire_bytes_length).To(&wire_bytes) ||
1499 !ReadVarint<uint32_t>().To(&compiled_bytes_length) ||
1500 compiled_bytes_length > max_valid_size ||
1501 !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) {
1502 return MaybeHandle<JSObject>();
1503 }
1504
1505 // Try to deserialize the compiled module first.
1506 ScriptData script_data(compiled_bytes.start(), compiled_bytes.length());
1507 Handle<FixedArray> compiled_part;
1508 if (WasmCompiledModuleSerializer::DeserializeWasmModule(
1509 isolate_, &script_data, wire_bytes)
1510 .ToHandle(&compiled_part)) {
1511 return wasm::CreateWasmModuleObject(
1512 isolate_, Handle<wasm::WasmCompiledModule>::cast(compiled_part),
1513 wasm::ModuleOrigin::kWasmOrigin);
1514 }
1515
1516 // If that fails, recompile.
1517 wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
1518 return wasm::CreateModuleObjectFromBytes(
1519 isolate_, wire_bytes.begin(), wire_bytes.end(), &thrower,
1520 wasm::ModuleOrigin::kWasmOrigin, Handle<Script>::null(), nullptr,
1521 nullptr);
1522 }
1523
1432 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { 1524 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
1433 if (!delegate_) return MaybeHandle<JSObject>(); 1525 if (!delegate_) return MaybeHandle<JSObject>();
1434 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); 1526 STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1435 uint32_t id = next_id_++; 1527 uint32_t id = next_id_++;
1436 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 1528 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1437 v8::Local<v8::Object> object; 1529 v8::Local<v8::Object> object;
1438 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { 1530 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
1439 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); 1531 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1440 return MaybeHandle<JSObject>(); 1532 return MaybeHandle<JSObject>();
1441 } 1533 }
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1733 if (stack.size() != 1) { 1825 if (stack.size() != 1) {
1734 isolate_->Throw(*isolate_->factory()->NewError( 1826 isolate_->Throw(*isolate_->factory()->NewError(
1735 MessageTemplate::kDataCloneDeserializationError)); 1827 MessageTemplate::kDataCloneDeserializationError));
1736 return MaybeHandle<Object>(); 1828 return MaybeHandle<Object>();
1737 } 1829 }
1738 return scope.CloseAndEscape(stack[0]); 1830 return scope.CloseAndEscape(stack[0]);
1739 } 1831 }
1740 1832
1741 } // namespace internal 1833 } // namespace internal
1742 } // namespace v8 1834 } // namespace v8
OLDNEW
« 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