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/factory.h" | 10 #include "src/factory.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 kInt32 = 'I', | 47 kInt32 = 'I', |
48 // Number represented as 32-bit unsigned integer, varint-encoded | 48 // Number represented as 32-bit unsigned integer, varint-encoded |
49 // (like uint32 in protobuf) | 49 // (like uint32 in protobuf) |
50 kUint32 = 'U', | 50 kUint32 = 'U', |
51 // Number represented as a 64-bit double. | 51 // Number represented as a 64-bit double. |
52 // Host byte order is used (N.B. this makes the format non-portable). | 52 // Host byte order is used (N.B. this makes the format non-portable). |
53 kDouble = 'N', | 53 kDouble = 'N', |
54 // byteLength:uint32_t, then raw data | 54 // byteLength:uint32_t, then raw data |
55 kUtf8String = 'S', | 55 kUtf8String = 'S', |
56 kTwoByteString = 'c', | 56 kTwoByteString = 'c', |
57 // Reference to a serialized object. objectID:uint32_t | |
58 kObjectReference = '^', | |
59 // Beginning of a JS object. | |
60 kBeginJSObject = 'o', | |
61 // End of a JS object. numProperties:uint32_t | |
62 kEndJSObject = '{', | |
57 }; | 63 }; |
58 | 64 |
59 ValueSerializer::ValueSerializer() {} | 65 ValueSerializer::ValueSerializer(Isolate* isolate) |
66 : isolate_(isolate), | |
67 zone_(isolate->allocator()), | |
68 id_map_(isolate->heap(), &zone_) {} | |
60 | 69 |
61 ValueSerializer::~ValueSerializer() {} | 70 ValueSerializer::~ValueSerializer() {} |
62 | 71 |
63 void ValueSerializer::WriteHeader() { | 72 void ValueSerializer::WriteHeader() { |
64 WriteTag(SerializationTag::kVersion); | 73 WriteTag(SerializationTag::kVersion); |
65 WriteVarint(kLatestVersion); | 74 WriteVarint(kLatestVersion); |
66 } | 75 } |
67 | 76 |
68 void ValueSerializer::WriteTag(SerializationTag tag) { | 77 void ValueSerializer::WriteTag(SerializationTag tag) { |
69 buffer_.push_back(static_cast<uint8_t>(tag)); | 78 buffer_.push_back(static_cast<uint8_t>(tag)); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 WriteOddball(Oddball::cast(*object)); | 146 WriteOddball(Oddball::cast(*object)); |
138 return Just(true); | 147 return Just(true); |
139 case HEAP_NUMBER_TYPE: | 148 case HEAP_NUMBER_TYPE: |
140 case MUTABLE_HEAP_NUMBER_TYPE: | 149 case MUTABLE_HEAP_NUMBER_TYPE: |
141 WriteHeapNumber(HeapNumber::cast(*object)); | 150 WriteHeapNumber(HeapNumber::cast(*object)); |
142 return Just(true); | 151 return Just(true); |
143 default: | 152 default: |
144 if (object->IsString()) { | 153 if (object->IsString()) { |
145 WriteString(Handle<String>::cast(object)); | 154 WriteString(Handle<String>::cast(object)); |
146 return Just(true); | 155 return Just(true); |
156 } else if (object->IsJSReceiver()) { | |
157 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); | |
147 } | 158 } |
148 UNIMPLEMENTED(); | 159 UNIMPLEMENTED(); |
149 return Nothing<bool>(); | 160 return Nothing<bool>(); |
150 } | 161 } |
151 } | 162 } |
152 | 163 |
153 void ValueSerializer::WriteOddball(Oddball* oddball) { | 164 void ValueSerializer::WriteOddball(Oddball* oddball) { |
154 SerializationTag tag = SerializationTag::kUndefined; | 165 SerializationTag tag = SerializationTag::kUndefined; |
155 switch (oddball->kind()) { | 166 switch (oddball->kind()) { |
156 case Oddball::kUndefined: | 167 case Oddball::kUndefined: |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 // The existing reading code expects 16-byte strings to be aligned. | 222 // The existing reading code expects 16-byte strings to be aligned. |
212 if ((buffer_.size() + 1 + BytesNeededForVarint(byte_length)) & 1) | 223 if ((buffer_.size() + 1 + BytesNeededForVarint(byte_length)) & 1) |
213 WriteTag(SerializationTag::kPadding); | 224 WriteTag(SerializationTag::kPadding); |
214 WriteTag(SerializationTag::kTwoByteString); | 225 WriteTag(SerializationTag::kTwoByteString); |
215 WriteTwoByteString(chars); | 226 WriteTwoByteString(chars); |
216 } else { | 227 } else { |
217 UNREACHABLE(); | 228 UNREACHABLE(); |
218 } | 229 } |
219 } | 230 } |
220 | 231 |
232 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { | |
233 // If the object has already been serialized, just write its ID. | |
234 uint32_t* id_map_entry = id_map_.Get(receiver); | |
235 if (uint32_t id = *id_map_entry) { | |
236 WriteTag(SerializationTag::kObjectReference); | |
237 WriteVarint(id - 1); | |
238 return Just(true); | |
239 } | |
240 | |
241 // Otherwise, allocate an ID for it. | |
242 uint32_t id = next_id_++; | |
243 *id_map_entry = id + 1; | |
244 | |
245 // Eliminate callable and exotic objects, which should not be serialized. | |
246 InstanceType instance_type = receiver->map()->instance_type(); | |
247 if (receiver->IsCallable() || instance_type <= LAST_SPECIAL_RECEIVER_TYPE) | |
248 return Nothing<bool>(); | |
Jakob Kummerow
2016/08/17 13:00:14
nit: braces are still missing.
(V8 style differs f
jbroman
2016/08/17 14:05:09
Done.
| |
249 | |
250 // If we are at the end of the stack, abort. This function may recurse. | |
251 if (StackLimitCheck(isolate_).HasOverflowed()) return Nothing<bool>(); | |
252 | |
253 HandleScope scope(isolate_); | |
254 switch (instance_type) { | |
255 case JS_OBJECT_TYPE: | |
256 case JS_API_OBJECT_TYPE: | |
257 return WriteJSObject(Handle<JSObject>::cast(receiver)); | |
258 default: | |
259 UNIMPLEMENTED(); | |
260 break; | |
261 } | |
262 return Nothing<bool>(); | |
263 } | |
264 | |
265 Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) { | |
266 WriteTag(SerializationTag::kBeginJSObject); | |
267 Handle<FixedArray> keys; | |
268 uint32_t properties_written; | |
269 if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, | |
270 ENUMERABLE_STRINGS) | |
271 .ToHandle(&keys) || | |
272 !WriteJSObjectProperties(object, keys).To(&properties_written)) { | |
273 return Nothing<bool>(); | |
274 } | |
275 WriteTag(SerializationTag::kEndJSObject); | |
276 WriteVarint<uint32_t>(properties_written); | |
277 return Just(true); | |
278 } | |
279 | |
280 Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties( | |
281 Handle<JSObject> object, Handle<FixedArray> keys) { | |
282 uint32_t properties_written = 0; | |
283 int length = keys->length(); | |
284 for (int i = 0; i < length; i++) { | |
285 Handle<Object> key(keys->get(i), isolate_); | |
286 | |
287 bool success; | |
288 LookupIterator it = LookupIterator::PropertyOrElement( | |
289 isolate_, object, key, &success, LookupIterator::OWN); | |
290 DCHECK(success); | |
291 Handle<Object> value; | |
292 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>(); | |
293 | |
294 // If the property is no longer found, do not serialize it. | |
295 // This could happen if a getter deleted the property. | |
296 if (!it.IsFound()) continue; | |
297 | |
298 if (!WriteObject(key).FromMaybe(false) || | |
299 !WriteObject(value).FromMaybe(false)) { | |
300 return Nothing<uint32_t>(); | |
301 } | |
302 | |
303 properties_written++; | |
304 } | |
305 return Just(properties_written); | |
306 } | |
307 | |
221 ValueDeserializer::ValueDeserializer(Isolate* isolate, | 308 ValueDeserializer::ValueDeserializer(Isolate* isolate, |
222 Vector<const uint8_t> data) | 309 Vector<const uint8_t> data) |
223 : isolate_(isolate), | 310 : isolate_(isolate), |
224 position_(data.start()), | 311 position_(data.start()), |
225 end_(data.start() + data.length()) {} | 312 end_(data.start() + data.length()), |
313 id_map_(Handle<SeededNumberDictionary>::cast( | |
314 isolate->global_handles()->Create( | |
315 *SeededNumberDictionary::New(isolate, 0)))) {} | |
226 | 316 |
227 ValueDeserializer::~ValueDeserializer() {} | 317 ValueDeserializer::~ValueDeserializer() { |
318 GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location()); | |
319 } | |
228 | 320 |
229 Maybe<bool> ValueDeserializer::ReadHeader() { | 321 Maybe<bool> ValueDeserializer::ReadHeader() { |
230 if (position_ < end_ && | 322 if (position_ < end_ && |
231 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) { | 323 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) { |
232 ReadTag().ToChecked(); | 324 ReadTag().ToChecked(); |
233 if (!ReadVarint<uint32_t>().To(&version_)) return Nothing<bool>(); | 325 if (!ReadVarint<uint32_t>().To(&version_)) return Nothing<bool>(); |
234 if (version_ > kLatestVersion) return Nothing<bool>(); | 326 if (version_ > kLatestVersion) return Nothing<bool>(); |
235 } | 327 } |
236 return Just(true); | 328 return Just(true); |
237 } | 329 } |
238 | 330 |
331 Maybe<SerializationTag> ValueDeserializer::PeekTag() const { | |
332 const uint8_t* peek_position = position_; | |
333 SerializationTag tag; | |
334 do { | |
335 if (peek_position >= end_) return Nothing<SerializationTag>(); | |
336 tag = static_cast<SerializationTag>(*peek_position); | |
337 peek_position++; | |
338 } while (tag == SerializationTag::kPadding); | |
339 return Just(tag); | |
340 } | |
341 | |
239 Maybe<SerializationTag> ValueDeserializer::ReadTag() { | 342 Maybe<SerializationTag> ValueDeserializer::ReadTag() { |
240 SerializationTag tag; | 343 SerializationTag tag; |
241 do { | 344 do { |
242 if (position_ >= end_) return Nothing<SerializationTag>(); | 345 if (position_ >= end_) return Nothing<SerializationTag>(); |
243 tag = static_cast<SerializationTag>(*position_); | 346 tag = static_cast<SerializationTag>(*position_); |
244 position_++; | 347 position_++; |
245 } while (tag == SerializationTag::kPadding); | 348 } while (tag == SerializationTag::kPadding); |
246 return Just(tag); | 349 return Just(tag); |
247 } | 350 } |
248 | 351 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
330 } | 433 } |
331 case SerializationTag::kDouble: { | 434 case SerializationTag::kDouble: { |
332 Maybe<double> number = ReadDouble(); | 435 Maybe<double> number = ReadDouble(); |
333 if (number.IsNothing()) return MaybeHandle<Object>(); | 436 if (number.IsNothing()) return MaybeHandle<Object>(); |
334 return isolate_->factory()->NewNumber(number.FromJust()); | 437 return isolate_->factory()->NewNumber(number.FromJust()); |
335 } | 438 } |
336 case SerializationTag::kUtf8String: | 439 case SerializationTag::kUtf8String: |
337 return ReadUtf8String(); | 440 return ReadUtf8String(); |
338 case SerializationTag::kTwoByteString: | 441 case SerializationTag::kTwoByteString: |
339 return ReadTwoByteString(); | 442 return ReadTwoByteString(); |
443 case SerializationTag::kObjectReference: { | |
444 uint32_t id; | |
445 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); | |
446 return GetObjectWithID(id); | |
447 } | |
448 case SerializationTag::kBeginJSObject: | |
449 return ReadJSObject(); | |
340 default: | 450 default: |
341 return MaybeHandle<Object>(); | 451 return MaybeHandle<Object>(); |
342 } | 452 } |
343 } | 453 } |
344 | 454 |
345 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { | 455 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { |
346 uint32_t utf8_length; | 456 uint32_t utf8_length; |
347 Vector<const uint8_t> utf8_bytes; | 457 Vector<const uint8_t> utf8_bytes; |
348 if (!ReadVarint<uint32_t>().To(&utf8_length) || | 458 if (!ReadVarint<uint32_t>().To(&utf8_length) || |
349 utf8_length > | 459 utf8_length > |
(...skipping 20 matching lines...) Expand all Loading... | |
370 ->NewRawTwoByteString(byte_length / sizeof(uc16)) | 480 ->NewRawTwoByteString(byte_length / sizeof(uc16)) |
371 .ToHandle(&string)) | 481 .ToHandle(&string)) |
372 return MaybeHandle<String>(); | 482 return MaybeHandle<String>(); |
373 | 483 |
374 // Copy the bytes directly into the new string. | 484 // Copy the bytes directly into the new string. |
375 // Warning: this uses host endianness. | 485 // Warning: this uses host endianness. |
376 memcpy(string->GetChars(), bytes.begin(), bytes.length()); | 486 memcpy(string->GetChars(), bytes.begin(), bytes.length()); |
377 return string; | 487 return string; |
378 } | 488 } |
379 | 489 |
490 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { | |
491 // If we are at the end of the stack, abort. This function may recurse. | |
492 if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSObject>(); | |
493 | |
494 uint32_t id = next_id_++; | |
495 HandleScope scope(isolate_); | |
496 Handle<JSObject> object = | |
497 isolate_->factory()->NewJSObject(isolate_->object_function()); | |
498 AddObjectWithID(id, object); | |
499 | |
500 uint32_t num_properties; | |
501 uint32_t expected_num_properties; | |
502 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject) | |
503 .To(&num_properties) || | |
504 !ReadVarint<uint32_t>().To(&expected_num_properties) || | |
505 num_properties != expected_num_properties) { | |
506 return MaybeHandle<JSObject>(); | |
507 } | |
508 | |
509 DCHECK(HasObjectWithID(id)); | |
510 return scope.CloseAndEscape(object); | |
511 } | |
512 | |
513 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( | |
514 Handle<JSObject> object, SerializationTag end_tag) { | |
515 for (uint32_t num_properties = 0;; num_properties++) { | |
516 SerializationTag tag; | |
517 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); | |
518 if (tag == end_tag) { | |
519 SerializationTag consumed_tag = ReadTag().ToChecked(); | |
520 USE(consumed_tag); | |
521 DCHECK(tag == consumed_tag); | |
522 return Just(num_properties); | |
523 } | |
524 | |
525 Handle<Object> key; | |
526 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>(); | |
527 Handle<Object> value; | |
528 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>(); | |
529 | |
530 bool success; | |
531 LookupIterator it = LookupIterator::PropertyOrElement( | |
532 isolate_, object, key, &success, LookupIterator::OWN); | |
533 if (!success || | |
534 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE) | |
535 .is_null()) { | |
536 return Nothing<uint32_t>(); | |
537 } | |
538 } | |
539 } | |
540 | |
541 bool ValueDeserializer::HasObjectWithID(uint32_t id) { | |
542 return id_map_->Has(isolate_, id); | |
543 } | |
544 | |
545 MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) { | |
546 int index = id_map_->FindEntry(isolate_, id); | |
547 if (index == SeededNumberDictionary::kNotFound) { | |
548 return MaybeHandle<JSReceiver>(); | |
549 } | |
550 Object* value = id_map_->ValueAt(index); | |
551 DCHECK(value->IsJSReceiver()); | |
552 return Handle<JSReceiver>(JSReceiver::cast(value), isolate_); | |
553 } | |
554 | |
555 void ValueDeserializer::AddObjectWithID(uint32_t id, | |
556 Handle<JSReceiver> object) { | |
557 DCHECK(!HasObjectWithID(id)); | |
558 const bool used_as_prototype = false; | |
559 Handle<SeededNumberDictionary> new_dictionary = | |
560 SeededNumberDictionary::AtNumberPut(id_map_, id, object, | |
561 used_as_prototype); | |
562 | |
563 // If the dictionary was reallocated, update the global handle. | |
564 if (!new_dictionary.is_identical_to(id_map_)) { | |
565 GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location()); | |
566 id_map_ = Handle<SeededNumberDictionary>::cast( | |
567 isolate_->global_handles()->Create(*new_dictionary)); | |
568 } | |
569 } | |
570 | |
380 } // namespace internal | 571 } // namespace internal |
381 } // namespace v8 | 572 } // namespace v8 |
OLD | NEW |