| Index: src/value-serializer.cc
|
| diff --git a/src/value-serializer.cc b/src/value-serializer.cc
|
| index 77ee124bb458ac2f8d4c2c495ff88ce39930cd1d..cf76ad25ed9d7e1887f52644a12f2bd3df524ff9 100644
|
| --- a/src/value-serializer.cc
|
| +++ b/src/value-serializer.cc
|
| @@ -19,13 +19,26 @@ namespace internal {
|
| static const uint32_t kLatestVersion = 9;
|
|
|
| enum class SerializationTag : uint8_t {
|
| + // version:uint32_t (if at beginning of data, sets version > 0)
|
| kVersion = 0xFF,
|
| + // ignore
|
| kPadding = '\0',
|
| + // refTableSize:uint32_t (previously used for sanity checks; safe to ignore)
|
| kVerifyObjectCount = '?',
|
| + // Oddballs (no data).
|
| kUndefined = '_',
|
| kNull = '0',
|
| kTrue = 'T',
|
| kFalse = 'F',
|
| + // Number represented as 32-bit integer, ZigZag-encoded
|
| + // (like sint32 in protobuf)
|
| + kInt32 = 'I',
|
| + // Number represented as 32-bit unsigned integer, varint-encoded
|
| + // (like uint32 in protobuf)
|
| + kUint32 = 'U',
|
| + // Number represented as a 64-bit double.
|
| + // Host byte order is used (N.B. this makes the format non-portable).
|
| + kDouble = 'N',
|
| };
|
|
|
| ValueSerializer::ValueSerializer() {}
|
| @@ -60,14 +73,40 @@ void ValueSerializer::WriteVarint(T value) {
|
| buffer_.insert(buffer_.end(), stack_buffer, next_byte);
|
| }
|
|
|
| +template <typename T>
|
| +void ValueSerializer::WriteZigZag(T value) {
|
| + // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
|
| + // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
|
| + // See also https://developers.google.com/protocol-buffers/docs/encoding
|
| + // Note that this implementation relies on the right shift being arithmetic.
|
| + static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
|
| + "Only signed integer types can be written as zigzag.");
|
| + using UnsignedT = typename std::make_unsigned<T>::type;
|
| + WriteVarint((static_cast<UnsignedT>(value) << 1) ^
|
| + (value >> (8 * sizeof(T) - 1)));
|
| +}
|
| +
|
| +void ValueSerializer::WriteDouble(double value) {
|
| + // Warning: this uses host endianness.
|
| + buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(&value),
|
| + reinterpret_cast<const uint8_t*>(&value + 1));
|
| +}
|
| +
|
| Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
|
| - if (object->IsSmi()) UNIMPLEMENTED();
|
| + if (object->IsSmi()) {
|
| + WriteSmi(Smi::cast(*object));
|
| + return Just(true);
|
| + }
|
|
|
| DCHECK(object->IsHeapObject());
|
| switch (HeapObject::cast(*object)->map()->instance_type()) {
|
| case ODDBALL_TYPE:
|
| WriteOddball(Oddball::cast(*object));
|
| return Just(true);
|
| + case HEAP_NUMBER_TYPE:
|
| + case MUTABLE_HEAP_NUMBER_TYPE:
|
| + WriteHeapNumber(HeapNumber::cast(*object));
|
| + return Just(true);
|
| default:
|
| UNIMPLEMENTED();
|
| return Nothing<bool>();
|
| @@ -96,6 +135,17 @@ void ValueSerializer::WriteOddball(Oddball* oddball) {
|
| WriteTag(tag);
|
| }
|
|
|
| +void ValueSerializer::WriteSmi(Smi* smi) {
|
| + static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits.");
|
| + WriteTag(SerializationTag::kInt32);
|
| + WriteZigZag<int32_t>(smi->value());
|
| +}
|
| +
|
| +void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
|
| + WriteTag(SerializationTag::kDouble);
|
| + WriteDouble(number->value());
|
| +}
|
| +
|
| ValueDeserializer::ValueDeserializer(Isolate* isolate,
|
| Vector<const uint8_t> data)
|
| : isolate_(isolate),
|
| @@ -149,6 +199,30 @@ Maybe<T> ValueDeserializer::ReadVarint() {
|
| return Just(value);
|
| }
|
|
|
| +template <typename T>
|
| +Maybe<T> ValueDeserializer::ReadZigZag() {
|
| + // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
|
| + // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
|
| + // See also https://developers.google.com/protocol-buffers/docs/encoding
|
| + static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
|
| + "Only signed integer types can be read as zigzag.");
|
| + using UnsignedT = typename std::make_unsigned<T>::type;
|
| + UnsignedT unsigned_value;
|
| + if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
|
| + return Just(static_cast<T>((unsigned_value >> 1) ^
|
| + -static_cast<T>(unsigned_value & 1)));
|
| +}
|
| +
|
| +Maybe<double> ValueDeserializer::ReadDouble() {
|
| + // Warning: this uses host endianness.
|
| + if (position_ > end_ - sizeof(double)) return Nothing<double>();
|
| + double value;
|
| + memcpy(&value, position_, sizeof(double));
|
| + position_ += sizeof(double);
|
| + if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
|
| + return Just(value);
|
| +}
|
| +
|
| MaybeHandle<Object> ValueDeserializer::ReadObject() {
|
| SerializationTag tag;
|
| if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
|
| @@ -165,6 +239,21 @@ MaybeHandle<Object> ValueDeserializer::ReadObject() {
|
| return isolate_->factory()->true_value();
|
| case SerializationTag::kFalse:
|
| return isolate_->factory()->false_value();
|
| + case SerializationTag::kInt32: {
|
| + Maybe<int32_t> number = ReadZigZag<int32_t>();
|
| + if (number.IsNothing()) return MaybeHandle<Object>();
|
| + return isolate_->factory()->NewNumberFromInt(number.FromJust());
|
| + }
|
| + case SerializationTag::kUint32: {
|
| + Maybe<uint32_t> number = ReadVarint<uint32_t>();
|
| + if (number.IsNothing()) return MaybeHandle<Object>();
|
| + return isolate_->factory()->NewNumberFromUint(number.FromJust());
|
| + }
|
| + case SerializationTag::kDouble: {
|
| + Maybe<double> number = ReadDouble();
|
| + if (number.IsNothing()) return MaybeHandle<Object>();
|
| + return isolate_->factory()->NewNumber(number.FromJust());
|
| + }
|
| default:
|
| return MaybeHandle<Object>();
|
| }
|
|
|