| 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 |