| Index: src/value-serializer.cc
|
| diff --git a/src/value-serializer.cc b/src/value-serializer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..77ee124bb458ac2f8d4c2c495ff88ce39930cd1d
|
| --- /dev/null
|
| +++ b/src/value-serializer.cc
|
| @@ -0,0 +1,174 @@
|
| +// 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) {
|
| + // Writes an unsigned integer as a base-128 varint.
|
| + // The number is written, 7 bits at a time, from the least significant to the
|
| + // most significant 7 bits. Each byte, except the last, has the MSB set.
|
| + // See also https://developers.google.com/protocol-buffers/docs/encoding
|
| + 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()) {
|
| + 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() {
|
| + // Reads an unsigned integer as a base-128 varint.
|
| + // The number is written, 7 bits at a time, from the least significant to the
|
| + // most significant 7 bits. Each byte, except the last, has the MSB set.
|
| + // If the varint is larger than T, any more significant bits are discarded.
|
| + // See also https://developers.google.com/protocol-buffers/docs/encoding
|
| + 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
|
|
|