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

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: nits 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
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>();
249 }
250
251 // If we are at the end of the stack, abort. This function may recurse.
252 if (StackLimitCheck(isolate_).HasOverflowed()) return Nothing<bool>();
253
254 HandleScope scope(isolate_);
255 switch (instance_type) {
256 case JS_OBJECT_TYPE:
257 case JS_API_OBJECT_TYPE:
258 return WriteJSObject(Handle<JSObject>::cast(receiver));
259 default:
260 UNIMPLEMENTED();
261 break;
262 }
263 return Nothing<bool>();
264 }
265
266 Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
267 WriteTag(SerializationTag::kBeginJSObject);
268 Handle<FixedArray> keys;
269 uint32_t properties_written;
270 if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
271 ENUMERABLE_STRINGS)
272 .ToHandle(&keys) ||
273 !WriteJSObjectProperties(object, keys).To(&properties_written)) {
274 return Nothing<bool>();
275 }
276 WriteTag(SerializationTag::kEndJSObject);
277 WriteVarint<uint32_t>(properties_written);
278 return Just(true);
279 }
280
281 Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
282 Handle<JSObject> object, Handle<FixedArray> keys) {
283 uint32_t properties_written = 0;
284 int length = keys->length();
285 for (int i = 0; i < length; i++) {
286 Handle<Object> key(keys->get(i), isolate_);
287
288 bool success;
289 LookupIterator it = LookupIterator::PropertyOrElement(
290 isolate_, object, key, &success, LookupIterator::OWN);
291 DCHECK(success);
292 Handle<Object> value;
293 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
294
295 // If the property is no longer found, do not serialize it.
296 // This could happen if a getter deleted the property.
297 if (!it.IsFound()) continue;
298
299 if (!WriteObject(key).FromMaybe(false) ||
300 !WriteObject(value).FromMaybe(false)) {
301 return Nothing<uint32_t>();
302 }
303
304 properties_written++;
305 }
306 return Just(properties_written);
307 }
308
221 ValueDeserializer::ValueDeserializer(Isolate* isolate, 309 ValueDeserializer::ValueDeserializer(Isolate* isolate,
222 Vector<const uint8_t> data) 310 Vector<const uint8_t> data)
223 : isolate_(isolate), 311 : isolate_(isolate),
224 position_(data.start()), 312 position_(data.start()),
225 end_(data.start() + data.length()) {} 313 end_(data.start() + data.length()),
314 id_map_(Handle<SeededNumberDictionary>::cast(
315 isolate->global_handles()->Create(
316 *SeededNumberDictionary::New(isolate, 0)))) {}
226 317
227 ValueDeserializer::~ValueDeserializer() {} 318 ValueDeserializer::~ValueDeserializer() {
319 GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location());
320 }
228 321
229 Maybe<bool> ValueDeserializer::ReadHeader() { 322 Maybe<bool> ValueDeserializer::ReadHeader() {
230 if (position_ < end_ && 323 if (position_ < end_ &&
231 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) { 324 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
232 ReadTag().ToChecked(); 325 ReadTag().ToChecked();
233 if (!ReadVarint<uint32_t>().To(&version_)) return Nothing<bool>(); 326 if (!ReadVarint<uint32_t>().To(&version_)) return Nothing<bool>();
234 if (version_ > kLatestVersion) return Nothing<bool>(); 327 if (version_ > kLatestVersion) return Nothing<bool>();
235 } 328 }
236 return Just(true); 329 return Just(true);
237 } 330 }
238 331
332 Maybe<SerializationTag> ValueDeserializer::PeekTag() const {
333 const uint8_t* peek_position = position_;
334 SerializationTag tag;
335 do {
336 if (peek_position >= end_) return Nothing<SerializationTag>();
337 tag = static_cast<SerializationTag>(*peek_position);
338 peek_position++;
339 } while (tag == SerializationTag::kPadding);
340 return Just(tag);
341 }
342
239 Maybe<SerializationTag> ValueDeserializer::ReadTag() { 343 Maybe<SerializationTag> ValueDeserializer::ReadTag() {
240 SerializationTag tag; 344 SerializationTag tag;
241 do { 345 do {
242 if (position_ >= end_) return Nothing<SerializationTag>(); 346 if (position_ >= end_) return Nothing<SerializationTag>();
243 tag = static_cast<SerializationTag>(*position_); 347 tag = static_cast<SerializationTag>(*position_);
244 position_++; 348 position_++;
245 } while (tag == SerializationTag::kPadding); 349 } while (tag == SerializationTag::kPadding);
246 return Just(tag); 350 return Just(tag);
247 } 351 }
248 352
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 } 434 }
331 case SerializationTag::kDouble: { 435 case SerializationTag::kDouble: {
332 Maybe<double> number = ReadDouble(); 436 Maybe<double> number = ReadDouble();
333 if (number.IsNothing()) return MaybeHandle<Object>(); 437 if (number.IsNothing()) return MaybeHandle<Object>();
334 return isolate_->factory()->NewNumber(number.FromJust()); 438 return isolate_->factory()->NewNumber(number.FromJust());
335 } 439 }
336 case SerializationTag::kUtf8String: 440 case SerializationTag::kUtf8String:
337 return ReadUtf8String(); 441 return ReadUtf8String();
338 case SerializationTag::kTwoByteString: 442 case SerializationTag::kTwoByteString:
339 return ReadTwoByteString(); 443 return ReadTwoByteString();
444 case SerializationTag::kObjectReference: {
445 uint32_t id;
446 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
447 return GetObjectWithID(id);
448 }
449 case SerializationTag::kBeginJSObject:
450 return ReadJSObject();
340 default: 451 default:
341 return MaybeHandle<Object>(); 452 return MaybeHandle<Object>();
342 } 453 }
343 } 454 }
344 455
345 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { 456 MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
346 uint32_t utf8_length; 457 uint32_t utf8_length;
347 Vector<const uint8_t> utf8_bytes; 458 Vector<const uint8_t> utf8_bytes;
348 if (!ReadVarint<uint32_t>().To(&utf8_length) || 459 if (!ReadVarint<uint32_t>().To(&utf8_length) ||
349 utf8_length > 460 utf8_length >
(...skipping 20 matching lines...) Expand all
370 ->NewRawTwoByteString(byte_length / sizeof(uc16)) 481 ->NewRawTwoByteString(byte_length / sizeof(uc16))
371 .ToHandle(&string)) 482 .ToHandle(&string))
372 return MaybeHandle<String>(); 483 return MaybeHandle<String>();
373 484
374 // Copy the bytes directly into the new string. 485 // Copy the bytes directly into the new string.
375 // Warning: this uses host endianness. 486 // Warning: this uses host endianness.
376 memcpy(string->GetChars(), bytes.begin(), bytes.length()); 487 memcpy(string->GetChars(), bytes.begin(), bytes.length());
377 return string; 488 return string;
378 } 489 }
379 490
491 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
492 // If we are at the end of the stack, abort. This function may recurse.
493 if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSObject>();
494
495 uint32_t id = next_id_++;
496 HandleScope scope(isolate_);
497 Handle<JSObject> object =
498 isolate_->factory()->NewJSObject(isolate_->object_function());
499 AddObjectWithID(id, object);
500
501 uint32_t num_properties;
502 uint32_t expected_num_properties;
503 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject)
504 .To(&num_properties) ||
505 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
506 num_properties != expected_num_properties) {
507 return MaybeHandle<JSObject>();
508 }
509
510 DCHECK(HasObjectWithID(id));
511 return scope.CloseAndEscape(object);
512 }
513
514 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
515 Handle<JSObject> object, SerializationTag end_tag) {
516 for (uint32_t num_properties = 0;; num_properties++) {
517 SerializationTag tag;
518 if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
519 if (tag == end_tag) {
520 SerializationTag consumed_tag = ReadTag().ToChecked();
521 USE(consumed_tag);
522 DCHECK(tag == consumed_tag);
523 return Just(num_properties);
524 }
525
526 Handle<Object> key;
527 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>();
528 Handle<Object> value;
529 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
530
531 bool success;
532 LookupIterator it = LookupIterator::PropertyOrElement(
533 isolate_, object, key, &success, LookupIterator::OWN);
534 if (!success ||
535 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
536 .is_null()) {
537 return Nothing<uint32_t>();
538 }
539 }
540 }
541
542 bool ValueDeserializer::HasObjectWithID(uint32_t id) {
543 return id_map_->Has(isolate_, id);
544 }
545
546 MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) {
547 int index = id_map_->FindEntry(isolate_, id);
548 if (index == SeededNumberDictionary::kNotFound) {
549 return MaybeHandle<JSReceiver>();
550 }
551 Object* value = id_map_->ValueAt(index);
552 DCHECK(value->IsJSReceiver());
553 return Handle<JSReceiver>(JSReceiver::cast(value), isolate_);
554 }
555
556 void ValueDeserializer::AddObjectWithID(uint32_t id,
557 Handle<JSReceiver> object) {
558 DCHECK(!HasObjectWithID(id));
559 const bool used_as_prototype = false;
560 Handle<SeededNumberDictionary> new_dictionary =
561 SeededNumberDictionary::AtNumberPut(id_map_, id, object,
562 used_as_prototype);
563
564 // If the dictionary was reallocated, update the global handle.
565 if (!new_dictionary.is_identical_to(id_map_)) {
566 GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location());
567 id_map_ = Handle<SeededNumberDictionary>::cast(
568 isolate_->global_handles()->Create(*new_dictionary));
569 }
570 }
571
380 } // namespace internal 572 } // namespace internal
381 } // namespace v8 573 } // namespace v8
OLDNEW
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698