Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: src/value-serializer.cc

Issue 2246093003: Blink-compatible serialization of dictionary-like objects. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: OptionalRescheduleException Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698