Chromium Code Reviews| Index: src/value-serializer.cc |
| diff --git a/src/value-serializer.cc b/src/value-serializer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..50fde61bdc73e7d067cc5429e55cd8f527770ae8 |
| --- /dev/null |
| +++ b/src/value-serializer.cc |
| @@ -0,0 +1,165 @@ |
| +// Copyright 2016 the V8 project authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "src/value-serializer.h" |
| + |
| +#include <type_traits> |
| + |
| +#include "src/base/logging.h" |
| +#include "src/factory.h" |
| +#include "src/handles-inl.h" |
| +#include "src/isolate.h" |
| +#include "src/objects-inl.h" |
| +#include "src/objects.h" |
| + |
| +namespace v8 { |
| +namespace internal { |
| + |
| +static const uint32_t kLatestVersion = 9; |
| + |
| +enum class SerializationTag : uint8_t { |
| + kVersion = 0xFF, |
| + kPadding = '\0', |
| + kVerifyObjectCount = '?', |
| + kUndefined = '_', |
| + kNull = '0', |
| + kTrue = 'T', |
| + kFalse = 'F', |
| +}; |
| + |
| +ValueSerializer::ValueSerializer() {} |
| + |
| +ValueSerializer::~ValueSerializer() {} |
| + |
| +void ValueSerializer::WriteHeader() { |
| + WriteTag(SerializationTag::kVersion); |
| + WriteVarint(kLatestVersion); |
| +} |
| + |
| +void ValueSerializer::WriteTag(SerializationTag tag) { |
| + buffer_.push_back(static_cast<uint8_t>(tag)); |
| +} |
| + |
| +template <typename T> |
| +void ValueSerializer::WriteVarint(T value) { |
| + static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, |
| + "Only unsigned integer types can be written as varints."); |
| + uint8_t stack_buffer[sizeof(T) * 8 / 7 + 1]; |
| + uint8_t* next_byte = &stack_buffer[0]; |
| + do { |
| + *next_byte = (value & 0x7f) | 0x80; |
| + next_byte++; |
| + value >>= 7; |
| + } while (value); |
| + *(next_byte - 1) &= 0x7f; |
| + buffer_.insert(buffer_.end(), stack_buffer, next_byte); |
| +} |
| + |
| +Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { |
| + if (object->IsSmi()) UNIMPLEMENTED(); |
| + |
| + DCHECK(object->IsHeapObject()); |
| + switch (HeapObject::cast(*object)->map()->instance_type()) { |
|
Camillo Bruni
2016/08/12 09:54:44
This is much slower than directly comparing agains
jbroman
2016/08/12 15:16:34
I'll be branching on the instance type of all obje
|
| + case ODDBALL_TYPE: |
| + WriteOddball(Oddball::cast(*object)); |
| + return Just(true); |
| + default: |
| + UNIMPLEMENTED(); |
| + return Nothing<bool>(); |
| + } |
| +} |
| + |
| +void ValueSerializer::WriteOddball(Oddball* oddball) { |
| + SerializationTag tag = SerializationTag::kUndefined; |
| + switch (oddball->kind()) { |
| + case Oddball::kUndefined: |
| + tag = SerializationTag::kUndefined; |
| + break; |
| + case Oddball::kFalse: |
| + tag = SerializationTag::kFalse; |
| + break; |
| + case Oddball::kTrue: |
| + tag = SerializationTag::kTrue; |
| + break; |
| + case Oddball::kNull: |
| + tag = SerializationTag::kNull; |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + WriteTag(tag); |
| +} |
| + |
| +ValueDeserializer::ValueDeserializer(Isolate* isolate, |
| + Vector<const uint8_t> data) |
| + : isolate_(isolate), |
| + position_(data.start()), |
| + end_(data.start() + data.length()) {} |
| + |
| +ValueDeserializer::~ValueDeserializer() {} |
| + |
| +Maybe<bool> ValueDeserializer::ReadHeader() { |
| + if (position_ < end_ && |
| + *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) { |
| + ReadTag().ToChecked(); |
| + if (!ReadVarint<uint32_t>().To(&version_)) return Nothing<bool>(); |
| + if (version_ > kLatestVersion) return Nothing<bool>(); |
| + } |
| + return Just(true); |
| +} |
| + |
| +Maybe<SerializationTag> ValueDeserializer::ReadTag() { |
| + SerializationTag tag; |
| + do { |
| + if (position_ >= end_) return Nothing<SerializationTag>(); |
| + tag = static_cast<SerializationTag>(*position_); |
| + position_++; |
| + } while (tag == SerializationTag::kPadding); |
| + return Just(tag); |
| +} |
| + |
| +template <typename T> |
| +Maybe<T> ValueDeserializer::ReadVarint() { |
| + static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, |
| + "Only unsigned integer types can be read as varints."); |
| + T value = 0; |
| + unsigned shift = 0; |
| + bool has_another_byte; |
| + do { |
| + if (position_ >= end_) return Nothing<T>(); |
| + uint8_t byte = *position_; |
| + if (V8_LIKELY(shift < sizeof(T) * 8)) { |
| + value |= (byte & 0x7f) << shift; |
| + shift += 7; |
| + } |
| + has_another_byte = byte & 0x80; |
| + position_++; |
| + } while (has_another_byte); |
| + return Just(value); |
| +} |
| + |
| +MaybeHandle<Object> ValueDeserializer::ReadObject() { |
| + SerializationTag tag; |
| + if (!ReadTag().To(&tag)) return MaybeHandle<Object>(); |
| + switch (tag) { |
| + case SerializationTag::kVerifyObjectCount: |
| + // Read the count and ignore it. |
| + if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>(); |
| + return ReadObject(); |
| + case SerializationTag::kUndefined: |
| + return isolate_->factory()->undefined_value(); |
| + case SerializationTag::kNull: |
| + return isolate_->factory()->null_value(); |
| + case SerializationTag::kTrue: |
| + return isolate_->factory()->true_value(); |
| + case SerializationTag::kFalse: |
| + return isolate_->factory()->false_value(); |
| + default: |
| + return MaybeHandle<Object>(); |
| + } |
| +} |
| + |
| +} // namespace internal |
| +} // namespace v8 |