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 |