Chromium Code Reviews| 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', | |
| 
 
Mircea Trofin
2016/11/03 23:30:05
oh, if we do it this way, might as well call it "R
 
jbroman
2016/11/04 14:32:12
Since this hasn't shipped, I suppose we could chan
 
 | |
| 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_serialize_wasm_modules && | 
| 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_serialize_wasm_modules) 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 const unsigned max_valid_size = std::numeric_limits<int>::max(); | |
| 
 
Mircea Trofin
2016/11/03 23:30:05
please use uint32_t instead of unsigned
 
jbroman
2016/11/04 14:32:12
This seemed more obviously correct (int -> unsigne
 
 | |
| 1490 uint32_t wire_bytes_length = 0; | |
| 1491 Vector<const uint8_t> wire_bytes; | |
| 1492 uint32_t compiled_bytes_length = 0; | |
| 1493 Vector<const uint8_t> compiled_bytes; | |
| 1494 if (!ReadVarint<uint32_t>().To(&wire_bytes_length) || | |
| 1495 wire_bytes_length > max_valid_size || | |
| 1496 !ReadRawBytes(wire_bytes_length).To(&wire_bytes) || | |
| 1497 !ReadVarint<uint32_t>().To(&compiled_bytes_length) || | |
| 1498 compiled_bytes_length > max_valid_size || | |
| 1499 !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) { | |
| 1500 return MaybeHandle<JSObject>(); | |
| 1501 } | |
| 1502 | |
| 1503 // Try to deserialize the compiled module first. | |
| 1504 ScriptData script_data(compiled_bytes.start(), compiled_bytes.length()); | |
| 1505 Handle<FixedArray> compiled_part; | |
| 1506 if (WasmCompiledModuleSerializer::DeserializeWasmModule( | |
| 1507 isolate_, &script_data, wire_bytes) | |
| 1508 .ToHandle(&compiled_part)) { | |
| 1509 return wasm::CreateWasmModuleObject( | |
| 1510 isolate_, Handle<wasm::WasmCompiledModule>::cast(compiled_part), | |
| 1511 wasm::ModuleOrigin::kWasmOrigin); | |
| 1512 } | |
| 1513 | |
| 1514 // If that fails, recompile. | |
| 1515 wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule"); | |
| 1516 return wasm::CreateModuleObjectFromBytes( | |
| 1517 isolate_, wire_bytes.begin(), wire_bytes.end(), &thrower, | |
| 1518 wasm::ModuleOrigin::kWasmOrigin, Handle<Script>::null(), nullptr, | |
| 1519 nullptr); | |
| 1520 } | |
| 1521 | |
| 1432 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { | 1522 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { | 
| 1433 if (!delegate_) return MaybeHandle<JSObject>(); | 1523 if (!delegate_) return MaybeHandle<JSObject>(); | 
| 1434 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); | 1524 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); | 
| 1435 uint32_t id = next_id_++; | 1525 uint32_t id = next_id_++; | 
| 1436 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 1526 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 
| 1437 v8::Local<v8::Object> object; | 1527 v8::Local<v8::Object> object; | 
| 1438 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { | 1528 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { | 
| 1439 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); | 1529 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); | 
| 1440 return MaybeHandle<JSObject>(); | 1530 return MaybeHandle<JSObject>(); | 
| 1441 } | 1531 } | 
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1733 if (stack.size() != 1) { | 1823 if (stack.size() != 1) { | 
| 1734 isolate_->Throw(*isolate_->factory()->NewError( | 1824 isolate_->Throw(*isolate_->factory()->NewError( | 
| 1735 MessageTemplate::kDataCloneDeserializationError)); | 1825 MessageTemplate::kDataCloneDeserializationError)); | 
| 1736 return MaybeHandle<Object>(); | 1826 return MaybeHandle<Object>(); | 
| 1737 } | 1827 } | 
| 1738 return scope.CloseAndEscape(stack[0]); | 1828 return scope.CloseAndEscape(stack[0]); | 
| 1739 } | 1829 } | 
| 1740 | 1830 | 
| 1741 } // namespace internal | 1831 } // namespace internal | 
| 1742 } // namespace v8 | 1832 } // namespace v8 | 
| OLD | NEW |