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 |