Commit d825492b authored by jbroman's avatar jbroman Committed by Commit bot

Support delegating serialization of host objects.

This exposes an interface for the embedder to provide a delegate which can
serialize or deserialize embedder-specific objects, like Blink's DOM wrappers.

BUG=chromium:148757

Review-Url: https://codereview.chromium.org/2327653002
Cr-Commit-Position: refs/heads/master@{#39422}
parent 05c4afb0
......@@ -1681,6 +1681,13 @@ class V8_EXPORT ValueSerializer {
* type.
*/
virtual void ThrowDataCloneError(Local<String> message) = 0;
/*
* The embedder overrides this method to write some kind of host object, if
* possible. If not, a suitable exception should be thrown and
* Nothing<bool>() returned.
*/
virtual Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object);
};
explicit ValueSerializer(Isolate* isolate);
......@@ -1718,6 +1725,15 @@ class V8_EXPORT ValueSerializer {
void TransferSharedArrayBuffer(uint32_t transfer_id,
Local<SharedArrayBuffer> shared_array_buffer);
/*
* Write raw data in various common formats to the buffer.
* Note that integer types are written in base-128 varint format, not with a
* binary copy. For use during an override of Delegate::WriteHostObject.
*/
void WriteUint32(uint32_t value);
void WriteUint64(uint64_t value);
void WriteRawBytes(const void* source, size_t length);
private:
ValueSerializer(const ValueSerializer&) = delete;
void operator=(const ValueSerializer&) = delete;
......@@ -1736,7 +1752,21 @@ class V8_EXPORT ValueSerializer {
*/
class V8_EXPORT ValueDeserializer {
public:
class V8_EXPORT Delegate {
public:
virtual ~Delegate() {}
/*
* The embedder overrides this method to read some kind of host object, if
* possible. If not, a suitable exception should be thrown and
* MaybeLocal<Object>() returned.
*/
virtual MaybeLocal<Object> ReadHostObject(Isolate* isolate);
};
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size);
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size,
Delegate* delegate);
~ValueDeserializer();
/*
......@@ -1781,6 +1811,15 @@ class V8_EXPORT ValueDeserializer {
*/
uint32_t GetWireFormatVersion() const;
/*
* Reads raw data in various common formats to the buffer.
* Note that integer types are read in base-128 varint format, not with a
* binary copy. For use during an override of Delegate::ReadHostObject.
*/
V8_WARN_UNUSED_RESULT bool ReadUint32(uint32_t* value);
V8_WARN_UNUSED_RESULT bool ReadUint64(uint64_t* value);
V8_WARN_UNUSED_RESULT bool ReadRawBytes(size_t length, const void** data);
private:
ValueDeserializer(const ValueDeserializer&) = delete;
void operator=(const ValueDeserializer&) = delete;
......
......@@ -2885,6 +2885,15 @@ MaybeLocal<String> JSON::Stringify(Local<Context> context,
// --- V a l u e S e r i a l i z a t i o n ---
Maybe<bool> ValueSerializer::Delegate::WriteHostObject(Isolate* v8_isolate,
Local<Object> object) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->ScheduleThrow(*isolate->factory()->NewError(
isolate->error_function(), i::MessageTemplate::kDataCloneError,
Utils::OpenHandle(*object)));
return Nothing<bool>();
}
struct ValueSerializer::PrivateData {
explicit PrivateData(i::Isolate* i, ValueSerializer::Delegate* delegate)
: isolate(i), serializer(i, delegate) {}
......@@ -2929,9 +2938,30 @@ void ValueSerializer::TransferSharedArrayBuffer(
transfer_id, Utils::OpenHandle(*shared_array_buffer));
}
void ValueSerializer::WriteUint32(uint32_t value) {
private_->serializer.WriteUint32(value);
}
void ValueSerializer::WriteUint64(uint64_t value) {
private_->serializer.WriteUint64(value);
}
void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
private_->serializer.WriteRawBytes(source, length);
}
MaybeLocal<Object> ValueDeserializer::Delegate::ReadHostObject(
Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->ScheduleThrow(*isolate->factory()->NewError(
isolate->error_function(),
i::MessageTemplate::kDataCloneDeserializationError));
return MaybeLocal<Object>();
}
struct ValueDeserializer::PrivateData {
PrivateData(i::Isolate* i, i::Vector<const uint8_t> data)
: isolate(i), deserializer(i, data) {}
PrivateData(i::Isolate* i, i::Vector<const uint8_t> data, Delegate* delegate)
: isolate(i), deserializer(i, data, delegate) {}
i::Isolate* isolate;
i::ValueDeserializer deserializer;
bool has_aborted = false;
......@@ -2939,14 +2969,18 @@ struct ValueDeserializer::PrivateData {
};
ValueDeserializer::ValueDeserializer(Isolate* isolate, const uint8_t* data,
size_t size) {
size_t size)
: ValueDeserializer(isolate, data, size, nullptr) {}
ValueDeserializer::ValueDeserializer(Isolate* isolate, const uint8_t* data,
size_t size, Delegate* delegate) {
if (base::IsValueInRangeForNumericType<int>(size)) {
private_ =
new PrivateData(reinterpret_cast<i::Isolate*>(isolate),
i::Vector<const uint8_t>(data, static_cast<int>(size)));
private_ = new PrivateData(
reinterpret_cast<i::Isolate*>(isolate),
i::Vector<const uint8_t>(data, static_cast<int>(size)), delegate);
} else {
private_ = new PrivateData(reinterpret_cast<i::Isolate*>(isolate),
i::Vector<const uint8_t>(nullptr, 0));
i::Vector<const uint8_t>(nullptr, 0), nullptr);
private_->has_aborted = true;
}
}
......@@ -3028,6 +3062,18 @@ void ValueDeserializer::TransferSharedArrayBuffer(
transfer_id, Utils::OpenHandle(*shared_array_buffer));
}
bool ValueDeserializer::ReadUint32(uint32_t* value) {
return private_->deserializer.ReadUint32(value);
}
bool ValueDeserializer::ReadUint64(uint64_t* value) {
return private_->deserializer.ReadUint64(value);
}
bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
return private_->deserializer.ReadRawBytes(length, data);
}
// --- D a t a ---
bool Value::FullIsUndefined() const {
......
......@@ -206,6 +206,14 @@ uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
return &buffer_[old_size];
}
void ValueSerializer::WriteUint32(uint32_t value) {
WriteVarint<uint32_t>(value);
}
void ValueSerializer::WriteUint64(uint64_t value) {
WriteVarint<uint64_t>(value);
}
void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
Handle<JSArrayBuffer> array_buffer) {
DCHECK(!array_buffer_transfer_map_.Find(array_buffer));
......@@ -353,8 +361,11 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
case JS_ARRAY_TYPE:
return WriteJSArray(Handle<JSArray>::cast(receiver));
case JS_OBJECT_TYPE:
case JS_API_OBJECT_TYPE:
return WriteJSObject(Handle<JSObject>::cast(receiver));
case JS_API_OBJECT_TYPE: {
Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
return js_object->GetInternalFieldCount() ? WriteHostObject(js_object)
: WriteJSObject(js_object);
}
case JS_DATE_TYPE:
WriteJSDate(JSDate::cast(*receiver));
return Just(true);
......@@ -701,6 +712,20 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) {
return Just(true);
}
Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) {
if (!delegate_) {
isolate_->Throw(*isolate_->factory()->NewError(
isolate_->error_function(), MessageTemplate::kDataCloneError, object));
return Nothing<bool>();
}
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
Maybe<bool> result =
delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
DCHECK(!result.IsNothing());
return result;
}
Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow(
Handle<JSObject> object, Handle<FixedArray> keys) {
uint32_t properties_written = 0;
......@@ -751,8 +776,10 @@ void ValueSerializer::ThrowDataCloneError(
}
ValueDeserializer::ValueDeserializer(Isolate* isolate,
Vector<const uint8_t> data)
Vector<const uint8_t> data,
v8::ValueDeserializer::Delegate* delegate)
: isolate_(isolate),
delegate_(delegate),
position_(data.start()),
end_(data.start() + data.length()),
pretenure_(data.length() > kPretenureThreshold ? TENURED : NOT_TENURED),
......@@ -865,6 +892,21 @@ Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
return Just(Vector<const uint8_t>(start, size));
}
bool ValueDeserializer::ReadUint32(uint32_t* value) {
return ReadVarint<uint32_t>().To(value);
}
bool ValueDeserializer::ReadUint64(uint64_t* value) {
return ReadVarint<uint64_t>().To(value);
}
bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
if (length > static_cast<size_t>(end_ - position_)) return false;
*data = position_;
position_ += length;
return true;
}
void ValueDeserializer::TransferArrayBuffer(
uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) {
if (array_buffer_transfer_map_.is_null()) {
......@@ -978,7 +1020,10 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
return ReadTransferredJSArrayBuffer(is_shared);
}
default:
return MaybeHandle<Object>();
// TODO(jbroman): Introduce an explicit tag for host objects to avoid
// having to treat every unknown tag as a potential host object.
position_--;
return ReadHostObject();
}
}
......@@ -1328,6 +1373,22 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
return typed_array;
}
MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
if (!delegate_) return MaybeHandle<JSObject>();
STACK_CHECK(isolate_, MaybeHandle<JSObject>());
uint32_t id = next_id_++;
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
v8::Local<v8::Object> object;
if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
return MaybeHandle<JSObject>();
}
Handle<JSObject> js_object =
Handle<JSObject>::cast(Utils::OpenHandle(*object));
AddObjectWithID(id, js_object);
return js_object;
}
Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
Handle<JSObject> object, SerializationTag end_tag) {
for (uint32_t num_properties = 0;; num_properties++) {
......
......@@ -69,6 +69,14 @@ class ValueSerializer {
void TransferArrayBuffer(uint32_t transfer_id,
Handle<JSArrayBuffer> array_buffer);
/*
* Publicly exposed wire format writing methods.
* These are intended for use within the delegate's WriteHostObject method.
*/
void WriteUint32(uint32_t value);
void WriteUint64(uint64_t value);
void WriteRawBytes(const void* source, size_t length);
private:
// Writing the wire format.
void WriteTag(SerializationTag tag);
......@@ -79,7 +87,6 @@ class ValueSerializer {
void WriteDouble(double value);
void WriteOneByteString(Vector<const uint8_t> chars);
void WriteTwoByteString(Vector<const uc16> chars);
void WriteRawBytes(const void* source, size_t length);
uint8_t* ReserveRawBytes(size_t bytes);
// Writing V8 objects of various kinds.
......@@ -98,6 +105,7 @@ class ValueSerializer {
Maybe<bool> WriteJSSet(Handle<JSSet> map) WARN_UNUSED_RESULT;
Maybe<bool> WriteJSArrayBuffer(JSArrayBuffer* array_buffer);
Maybe<bool> WriteJSArrayBufferView(JSArrayBufferView* array_buffer);
Maybe<bool> WriteHostObject(Handle<JSObject> object) WARN_UNUSED_RESULT;
/*
* Reads the specified keys from the object and writes key-value pairs to the
......@@ -138,7 +146,8 @@ class ValueSerializer {
*/
class ValueDeserializer {
public:
ValueDeserializer(Isolate* isolate, Vector<const uint8_t> data);
ValueDeserializer(Isolate* isolate, Vector<const uint8_t> data,
v8::ValueDeserializer::Delegate* delegate);
~ValueDeserializer();
/*
......@@ -175,6 +184,14 @@ class ValueDeserializer {
void TransferArrayBuffer(uint32_t transfer_id,
Handle<JSArrayBuffer> array_buffer);
/*
* Publicly exposed wire format writing methods.
* These are intended for use within the delegate's WriteHostObject method.
*/
bool ReadUint32(uint32_t* value) WARN_UNUSED_RESULT;
bool ReadUint64(uint64_t* value) WARN_UNUSED_RESULT;
bool ReadRawBytes(size_t length, const void** data) WARN_UNUSED_RESULT;
private:
// Reading the wire format.
Maybe<SerializationTag> PeekTag() const WARN_UNUSED_RESULT;
......@@ -208,6 +225,7 @@ class ValueDeserializer {
WARN_UNUSED_RESULT;
MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView(
Handle<JSArrayBuffer> buffer) WARN_UNUSED_RESULT;
MaybeHandle<JSObject> ReadHostObject() WARN_UNUSED_RESULT;
/*
* Reads key-value pairs into the object until the specified end tag is
......@@ -222,6 +240,7 @@ class ValueDeserializer {
void AddObjectWithID(uint32_t id, Handle<JSReceiver> object);
Isolate* const isolate_;
v8::ValueDeserializer::Delegate* const delegate_;
const uint8_t* position_;
const uint8_t* const end_;
PretenureFlag pretenure_;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment