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/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 |