OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |