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" |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 // ObjectReference to one) serialized just before it. This is a quirk arising | 119 // ObjectReference to one) serialized just before it. This is a quirk arising |
120 // from the previous stack-based implementation. | 120 // from the previous stack-based implementation. |
121 kArrayBufferView = 'V', | 121 kArrayBufferView = 'V', |
122 // Shared array buffer. transferID:uint32_t | 122 // Shared array buffer. transferID:uint32_t |
123 kSharedArrayBuffer = 'u', | 123 kSharedArrayBuffer = 'u', |
124 // Compiled WebAssembly module. encodingType:(one-byte tag). | 124 // Compiled WebAssembly module. encodingType:(one-byte tag). |
125 // If encodingType == 'y' (raw bytes): | 125 // If encodingType == 'y' (raw bytes): |
126 // wasmWireByteLength:uint32_t, then raw data | 126 // wasmWireByteLength:uint32_t, then raw data |
127 // compiledDataLength:uint32_t, then raw data | 127 // compiledDataLength:uint32_t, then raw data |
128 kWasmModule = 'W', | 128 kWasmModule = 'W', |
| 129 // A wasm module object transfer. next value is its index. |
| 130 kWasmModuleTransfer = 'w', |
129 // The delegate is responsible for processing all following data. | 131 // The delegate is responsible for processing all following data. |
130 // This "escapes" to whatever wire format the delegate chooses. | 132 // This "escapes" to whatever wire format the delegate chooses. |
131 kHostObject = '\\', | 133 kHostObject = '\\', |
132 }; | 134 }; |
133 | 135 |
134 namespace { | 136 namespace { |
135 | 137 |
136 enum class ArrayBufferViewTag : uint8_t { | 138 enum class ArrayBufferViewTag : uint8_t { |
137 kInt8Array = 'b', | 139 kInt8Array = 'b', |
138 kUint8Array = 'B', | 140 kUint8Array = 'B', |
(...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 DCHECK(view->IsJSDataView()); | 798 DCHECK(view->IsJSDataView()); |
797 tag = ArrayBufferViewTag::kDataView; | 799 tag = ArrayBufferViewTag::kDataView; |
798 } | 800 } |
799 WriteVarint(static_cast<uint8_t>(tag)); | 801 WriteVarint(static_cast<uint8_t>(tag)); |
800 WriteVarint(NumberToUint32(view->byte_offset())); | 802 WriteVarint(NumberToUint32(view->byte_offset())); |
801 WriteVarint(NumberToUint32(view->byte_length())); | 803 WriteVarint(NumberToUint32(view->byte_length())); |
802 return ThrowIfOutOfMemory(); | 804 return ThrowIfOutOfMemory(); |
803 } | 805 } |
804 | 806 |
805 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) { | 807 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) { |
| 808 if (delegate_ != nullptr) { |
| 809 Maybe<uint32_t> transfer_id = delegate_->GetWasmModuleTransferId( |
| 810 reinterpret_cast<v8::Isolate*>(isolate_), |
| 811 v8::Local<v8::WasmCompiledModule>::Cast(Utils::ToLocal(object))); |
| 812 uint32_t id = 0; |
| 813 if (transfer_id.To(&id)) { |
| 814 WriteTag(SerializationTag::kWasmModuleTransfer); |
| 815 WriteVarint<uint32_t>(id); |
| 816 return Just(true); |
| 817 } |
| 818 } |
| 819 |
806 Handle<WasmCompiledModule> compiled_part( | 820 Handle<WasmCompiledModule> compiled_part( |
807 WasmCompiledModule::cast(object->GetInternalField(0)), isolate_); | 821 WasmCompiledModule::cast(object->GetInternalField(0)), isolate_); |
808 WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes; | 822 WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes; |
809 WriteTag(SerializationTag::kWasmModule); | 823 WriteTag(SerializationTag::kWasmModule); |
810 WriteRawBytes(&encoding_tag, sizeof(encoding_tag)); | 824 WriteRawBytes(&encoding_tag, sizeof(encoding_tag)); |
811 | 825 |
812 Handle<String> wire_bytes(compiled_part->module_bytes(), isolate_); | 826 Handle<String> wire_bytes(compiled_part->module_bytes(), isolate_); |
813 int wire_bytes_length = wire_bytes->length(); | 827 int wire_bytes_length = wire_bytes->length(); |
814 WriteVarint<uint32_t>(wire_bytes_length); | 828 WriteVarint<uint32_t>(wire_bytes_length); |
815 uint8_t* destination; | 829 uint8_t* destination; |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 Handle<SeededNumberDictionary> new_dictionary = | 1061 Handle<SeededNumberDictionary> new_dictionary = |
1048 SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, array_buffer, | 1062 SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, array_buffer, |
1049 not_a_prototype_holder); | 1063 not_a_prototype_holder); |
1050 if (!new_dictionary.is_identical_to(dictionary)) { | 1064 if (!new_dictionary.is_identical_to(dictionary)) { |
1051 GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); | 1065 GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); |
1052 array_buffer_transfer_map_ = Handle<SeededNumberDictionary>::cast( | 1066 array_buffer_transfer_map_ = Handle<SeededNumberDictionary>::cast( |
1053 isolate_->global_handles()->Create(*new_dictionary)); | 1067 isolate_->global_handles()->Create(*new_dictionary)); |
1054 } | 1068 } |
1055 } | 1069 } |
1056 | 1070 |
| 1071 void ValueDeserializer::TransferWasmModule(uint32_t transfer_id, |
| 1072 Handle<WasmModuleObject> module) { |
| 1073 // We don't realistically expect too many wasm modules to be posted around. |
| 1074 // See v8:6106 also. |
| 1075 size_t necessary_size = Max(transferred_wasm_modules_.size(), |
| 1076 static_cast<size_t>(transfer_id + 1)); |
| 1077 if (transferred_wasm_modules_.size() < necessary_size) { |
| 1078 transferred_wasm_modules_.resize(necessary_size); |
| 1079 } |
| 1080 transferred_wasm_modules_[transfer_id] = module; |
| 1081 } |
| 1082 |
1057 MaybeHandle<Object> ValueDeserializer::ReadObject() { | 1083 MaybeHandle<Object> ValueDeserializer::ReadObject() { |
1058 MaybeHandle<Object> result = ReadObjectInternal(); | 1084 MaybeHandle<Object> result = ReadObjectInternal(); |
1059 | 1085 |
1060 // ArrayBufferView is special in that it consumes the value before it, even | 1086 // ArrayBufferView is special in that it consumes the value before it, even |
1061 // after format version 0. | 1087 // after format version 0. |
1062 Handle<Object> object; | 1088 Handle<Object> object; |
1063 SerializationTag tag; | 1089 SerializationTag tag; |
1064 if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) && | 1090 if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) && |
1065 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) { | 1091 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) { |
1066 ConsumeTag(SerializationTag::kArrayBufferView); | 1092 ConsumeTag(SerializationTag::kArrayBufferView); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1143 case SerializationTag::kArrayBufferTransfer: { | 1169 case SerializationTag::kArrayBufferTransfer: { |
1144 const bool is_shared = false; | 1170 const bool is_shared = false; |
1145 return ReadTransferredJSArrayBuffer(is_shared); | 1171 return ReadTransferredJSArrayBuffer(is_shared); |
1146 } | 1172 } |
1147 case SerializationTag::kSharedArrayBuffer: { | 1173 case SerializationTag::kSharedArrayBuffer: { |
1148 const bool is_shared = true; | 1174 const bool is_shared = true; |
1149 return ReadTransferredJSArrayBuffer(is_shared); | 1175 return ReadTransferredJSArrayBuffer(is_shared); |
1150 } | 1176 } |
1151 case SerializationTag::kWasmModule: | 1177 case SerializationTag::kWasmModule: |
1152 return ReadWasmModule(); | 1178 return ReadWasmModule(); |
| 1179 case SerializationTag::kWasmModuleTransfer: |
| 1180 return ReadWasmModuleTransfer(); |
1153 case SerializationTag::kHostObject: | 1181 case SerializationTag::kHostObject: |
1154 return ReadHostObject(); | 1182 return ReadHostObject(); |
1155 default: | 1183 default: |
1156 // Before there was an explicit tag for host objects, all unknown tags | 1184 // Before there was an explicit tag for host objects, all unknown tags |
1157 // were delegated to the host. | 1185 // were delegated to the host. |
1158 if (version_ < 13) { | 1186 if (version_ < 13) { |
1159 position_--; | 1187 position_--; |
1160 return ReadHostObject(); | 1188 return ReadHostObject(); |
1161 } | 1189 } |
1162 return MaybeHandle<Object>(); | 1190 return MaybeHandle<Object>(); |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1588 byte_length % element_size != 0) { | 1616 byte_length % element_size != 0) { |
1589 return MaybeHandle<JSArrayBufferView>(); | 1617 return MaybeHandle<JSArrayBufferView>(); |
1590 } | 1618 } |
1591 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( | 1619 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( |
1592 external_array_type, buffer, byte_offset, byte_length / element_size, | 1620 external_array_type, buffer, byte_offset, byte_length / element_size, |
1593 pretenure_); | 1621 pretenure_); |
1594 AddObjectWithID(id, typed_array); | 1622 AddObjectWithID(id, typed_array); |
1595 return typed_array; | 1623 return typed_array; |
1596 } | 1624 } |
1597 | 1625 |
| 1626 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() { |
| 1627 if (FLAG_wasm_disable_structured_cloning || allow_inline_wasm()) { |
| 1628 return MaybeHandle<JSObject>(); |
| 1629 } |
| 1630 |
| 1631 uint32_t index = 0; |
| 1632 if (ReadVarint<uint32_t>().To(&index) && |
| 1633 index < transferred_wasm_modules_.size()) { |
| 1634 Handle<JSObject> module = transferred_wasm_modules_[index]; |
| 1635 uint32_t id = next_id_++; |
| 1636 AddObjectWithID(id, module); |
| 1637 return module; |
| 1638 } else { |
| 1639 return MaybeHandle<JSObject>(); |
| 1640 } |
| 1641 } |
| 1642 |
1598 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() { | 1643 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() { |
1599 if (FLAG_wasm_disable_structured_cloning) return MaybeHandle<JSObject>(); | 1644 if (FLAG_wasm_disable_structured_cloning || !allow_inline_wasm()) { |
| 1645 return MaybeHandle<JSObject>(); |
| 1646 } |
1600 | 1647 |
1601 Vector<const uint8_t> encoding_tag; | 1648 Vector<const uint8_t> encoding_tag; |
1602 if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) || | 1649 if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) || |
1603 encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) { | 1650 encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) { |
1604 return MaybeHandle<JSObject>(); | 1651 return MaybeHandle<JSObject>(); |
1605 } | 1652 } |
1606 | 1653 |
1607 // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled | 1654 // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled |
1608 // script data. | 1655 // script data. |
1609 static_assert(sizeof(int) <= sizeof(uint32_t), | 1656 static_assert(sizeof(int) <= sizeof(uint32_t), |
1610 "max int must fit in uint32_t"); | 1657 "max int must fit in uint32_t"); |
1611 const uint32_t max_valid_size = std::numeric_limits<int>::max(); | 1658 const uint32_t max_valid_size = std::numeric_limits<int>::max(); |
1612 uint32_t wire_bytes_length = 0; | 1659 uint32_t wire_bytes_length = 0; |
1613 Vector<const uint8_t> wire_bytes; | 1660 Vector<const uint8_t> wire_bytes; |
1614 uint32_t compiled_bytes_length = 0; | 1661 uint32_t compiled_bytes_length = 0; |
1615 Vector<const uint8_t> compiled_bytes; | 1662 Vector<const uint8_t> compiled_bytes; |
1616 if (!ReadVarint<uint32_t>().To(&wire_bytes_length) || | 1663 if (!ReadVarint<uint32_t>().To(&wire_bytes_length) || |
1617 wire_bytes_length > max_valid_size || | 1664 wire_bytes_length > max_valid_size || |
1618 !ReadRawBytes(wire_bytes_length).To(&wire_bytes) || | 1665 !ReadRawBytes(wire_bytes_length).To(&wire_bytes) || |
1619 !ReadVarint<uint32_t>().To(&compiled_bytes_length) || | 1666 !ReadVarint<uint32_t>().To(&compiled_bytes_length) || |
1620 compiled_bytes_length > max_valid_size || | 1667 compiled_bytes_length > max_valid_size || |
1621 !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) { | 1668 !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) { |
1622 return MaybeHandle<JSObject>(); | 1669 return MaybeHandle<JSObject>(); |
1623 } | 1670 } |
1624 | 1671 |
1625 // Try to deserialize the compiled module first. | 1672 // Try to deserialize the compiled module first. |
1626 ScriptData script_data(compiled_bytes.start(), compiled_bytes.length()); | 1673 ScriptData script_data(compiled_bytes.start(), compiled_bytes.length()); |
1627 Handle<FixedArray> compiled_part; | 1674 Handle<FixedArray> compiled_part; |
| 1675 MaybeHandle<JSObject> result; |
1628 if (WasmCompiledModuleSerializer::DeserializeWasmModule( | 1676 if (WasmCompiledModuleSerializer::DeserializeWasmModule( |
1629 isolate_, &script_data, wire_bytes) | 1677 isolate_, &script_data, wire_bytes) |
1630 .ToHandle(&compiled_part)) { | 1678 .ToHandle(&compiled_part)) { |
1631 return WasmModuleObject::New( | 1679 result = WasmModuleObject::New( |
1632 isolate_, Handle<WasmCompiledModule>::cast(compiled_part)); | 1680 isolate_, Handle<WasmCompiledModule>::cast(compiled_part)); |
1633 } | 1681 } else { |
1634 | |
1635 // If that fails, recompile. | |
1636 MaybeHandle<JSObject> result; | |
1637 { | |
1638 wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule"); | 1682 wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule"); |
1639 result = wasm::SyncCompile(isolate_, &thrower, | 1683 result = wasm::SyncCompile(isolate_, &thrower, |
1640 wasm::ModuleWireBytes(wire_bytes)); | 1684 wasm::ModuleWireBytes(wire_bytes)); |
1641 } | 1685 } |
1642 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); | 1686 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); |
| 1687 uint32_t id = next_id_++; |
| 1688 if (!result.is_null()) { |
| 1689 AddObjectWithID(id, result.ToHandleChecked()); |
| 1690 } |
1643 return result; | 1691 return result; |
1644 } | 1692 } |
1645 | 1693 |
1646 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { | 1694 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { |
1647 if (!delegate_) return MaybeHandle<JSObject>(); | 1695 if (!delegate_) return MaybeHandle<JSObject>(); |
1648 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); | 1696 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); |
1649 uint32_t id = next_id_++; | 1697 uint32_t id = next_id_++; |
1650 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 1698 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); |
1651 v8::Local<v8::Object> object; | 1699 v8::Local<v8::Object> object; |
1652 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { | 1700 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1969 if (stack.size() != 1) { | 2017 if (stack.size() != 1) { |
1970 isolate_->Throw(*isolate_->factory()->NewError( | 2018 isolate_->Throw(*isolate_->factory()->NewError( |
1971 MessageTemplate::kDataCloneDeserializationError)); | 2019 MessageTemplate::kDataCloneDeserializationError)); |
1972 return MaybeHandle<Object>(); | 2020 return MaybeHandle<Object>(); |
1973 } | 2021 } |
1974 return scope.CloseAndEscape(stack[0]); | 2022 return scope.CloseAndEscape(stack[0]); |
1975 } | 2023 } |
1976 | 2024 |
1977 } // namespace internal | 2025 } // namespace internal |
1978 } // namespace v8 | 2026 } // namespace v8 |
OLD | NEW |