Commit 8687a214 authored by jbroman's avatar jbroman Committed by Commit bot

Move V8-based serialization into dedicated classes and add support for ArrayBuffer transfer.

Eventually these classes are intended to replace ScriptValueSerializer and
ScriptValueDeserializer as they exist today.

BUG=chromium:148757

Review-Url: https://codereview.chromium.org/2305703002
Cr-Commit-Position: refs/heads/master@{#416445}
parent 5b92337e
......@@ -735,29 +735,6 @@ static void recordValueCounts(int primitiveCount, int jsObjectCount, int domWrap
PassRefPtr<SerializedScriptValue> ScriptValueSerializer::serialize(v8::Local<v8::Value> value, Transferables* transferables, ExceptionState& exceptionState)
{
if (RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled()) {
v8::HandleScope scope(isolate());
v8::ValueSerializer serializer(isolate());
serializer.WriteHeader();
bool wroteValue;
if (!serializer.WriteValue(context(), value).To(&wroteValue)) {
// TODO(jbroman): Revisit how DataCloneError is thrown.
// https://crbug.com/641964
if (m_tryCatch.HasCaught()) {
exceptionState.rethrowV8Exception(m_tryCatch.Exception());
} else {
exceptionState.throwDOMException(DataCloneError, "An object could not be cloned.");
}
return nullptr;
}
DCHECK(wroteValue);
std::vector<uint8_t> buffer = serializer.ReleaseBuffer();
// TODO(jbroman): Remove this old conversion to WTF::String.
if (buffer.size() % 2)
buffer.push_back(0);
return SerializedScriptValue::create(String(reinterpret_cast<const UChar*>(&buffer[0]), buffer.size() / 2));
}
m_primitiveCount = m_jsObjectCount = m_domWrapperCount = 0;
DCHECK(!m_blobDataHandles);
......@@ -2196,23 +2173,6 @@ PassRefPtr<BlobDataHandle> SerializedScriptValueReader::getOrCreateBlobDataHandl
v8::Local<v8::Value> ScriptValueDeserializer::deserialize()
{
v8::Isolate* isolate = m_reader.getScriptState()->isolate();
if (RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled()) {
v8::EscapableHandleScope scope(isolate);
v8::TryCatch tryCatch(isolate);
v8::ValueDeserializer deserializer(isolate, m_reader.buffer(), m_reader.length());
deserializer.SetSupportsLegacyWireFormat(true);
bool readHeader;
if (!deserializer.ReadHeader().To(&readHeader))
return v8::Null(isolate);
DCHECK(readHeader);
v8::Local<v8::Context> context = m_reader.getScriptState()->context();
v8::Local<v8::Value> value;
if (!deserializer.ReadValue(context).ToLocal(&value))
return v8::Null(isolate);
return scope.Escape(value);
}
if (!m_reader.readVersion(m_version) || m_version > SerializedScriptValue::wireFormatVersion)
return v8::Null(isolate);
m_reader.setVersion(m_version);
......
......@@ -484,14 +484,10 @@ public:
bool readVersion(uint32_t& version);
void setVersion(uint32_t);
// Used to extract the underlying buffer, in order to bypass
// SerializedScriptValueReader.
const uint8_t* buffer() const { return m_buffer; }
unsigned length() const { return m_length; }
protected:
v8::Isolate* isolate() const { return m_scriptState->isolate(); }
v8::Local<v8::Context> context() const { return m_scriptState->context(); }
unsigned length() const { return m_length; }
unsigned position() const { return m_position; }
const uint8_t* allocate(uint32_t size)
......
......@@ -42,6 +42,8 @@
#include "bindings/core/v8/V8MessagePort.h"
#include "bindings/core/v8/V8OffscreenCanvas.h"
#include "bindings/core/v8/V8SharedArrayBuffer.h"
#include "bindings/core/v8/serialization/V8ScriptValueDeserializer.h"
#include "bindings/core/v8/serialization/V8ScriptValueSerializer.h"
#include "core/dom/DOMArrayBuffer.h"
#include "core/dom/DOMSharedArrayBuffer.h"
#include "core/dom/ExceptionCode.h"
......@@ -62,6 +64,12 @@ namespace blink {
PassRefPtr<SerializedScriptValue> SerializedScriptValue::serialize(v8::Isolate* isolate, v8::Local<v8::Value> value, Transferables* transferables, WebBlobInfoArray* blobInfo, ExceptionState& exception)
{
// TODO(jbroman): Move the V8-based structured clone invocation into
// SerializedScriptValueFactory.
if (RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled()) {
V8ScriptValueSerializer serializer(ScriptState::current(isolate));
return serializer.serialize(value, transferables, exception);
}
return SerializedScriptValueFactory::instance().create(isolate, value, transferables, blobInfo, exception);
}
......@@ -270,6 +278,12 @@ v8::Local<v8::Value> SerializedScriptValue::deserialize(MessagePortArray* messag
v8::Local<v8::Value> SerializedScriptValue::deserialize(v8::Isolate* isolate, MessagePortArray* messagePorts, const WebBlobInfoArray* blobInfo)
{
// TODO(jbroman): Move the V8-based structured clone invocation into
// SerializedScriptValueFactory.
if (RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled()) {
V8ScriptValueDeserializer deserializer(ScriptState::current(isolate), this);
return deserializer.deserialize();
}
return SerializedScriptValueFactory::instance().deserialize(this, isolate, messagePorts, blobInfo);
}
......
......@@ -113,6 +113,7 @@ public:
private:
friend class ScriptValueSerializer;
friend class V8ScriptValueSerializer;
enum StringDataMode {
StringValue,
......
// Copyright 2016 The Chromium 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 "bindings/core/v8/serialization/V8ScriptValueDeserializer.h"
#include "bindings/core/v8/ToV8.h"
#include "core/dom/DOMArrayBuffer.h"
#include "core/dom/DOMSharedArrayBuffer.h"
#include "platform/RuntimeEnabledFeatures.h"
namespace blink {
V8ScriptValueDeserializer::V8ScriptValueDeserializer(RefPtr<ScriptState> scriptState, RefPtr<SerializedScriptValue> serializedScriptValue)
: m_scriptState(std::move(scriptState))
, m_serializedScriptValue(std::move(serializedScriptValue))
, m_deserializer(
m_scriptState->isolate(),
reinterpret_cast<const uint8_t*>(
m_serializedScriptValue->data().ensure16Bit(),
m_serializedScriptValue->data().characters16()),
m_serializedScriptValue->data().length() * 2)
{
DCHECK(RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled());
m_deserializer.SetSupportsLegacyWireFormat(true);
}
v8::Local<v8::Value> V8ScriptValueDeserializer::deserialize()
{
#if DCHECK_IS_ON()
DCHECK(!m_deserializeInvoked);
m_deserializeInvoked = true;
#endif
v8::Isolate* isolate = m_scriptState->isolate();
v8::EscapableHandleScope scope(isolate);
v8::TryCatch tryCatch(isolate);
v8::Local<v8::Context> context = m_scriptState->context();
bool readHeader;
if (!m_deserializer.ReadHeader().To(&readHeader))
return v8::Null(isolate);
DCHECK(readHeader);
m_version = m_deserializer.GetWireFormatVersion();
// Prepare to transfer the provided transferables.
transfer();
v8::Local<v8::Value> value;
if (!m_deserializer.ReadValue(context).ToLocal(&value))
return v8::Null(isolate);
return scope.Escape(value);
}
void V8ScriptValueDeserializer::transfer()
{
v8::Isolate* isolate = m_scriptState->isolate();
v8::Local<v8::Context> context = m_scriptState->context();
v8::Local<v8::Object> creationContext = context->Global();
// Transfer array buffers.
if (auto* arrayBufferContents = m_serializedScriptValue->getArrayBufferContentsArray()) {
for (unsigned i = 0; i < arrayBufferContents->size(); i++) {
WTF::ArrayBufferContents& contents = arrayBufferContents->at(i);
if (contents.isShared()) {
DOMSharedArrayBuffer* arrayBuffer = DOMSharedArrayBuffer::create(contents);
v8::Local<v8::Value> wrapper = toV8(arrayBuffer, creationContext, isolate);
DCHECK(wrapper->IsSharedArrayBuffer());
m_deserializer.TransferSharedArrayBuffer(
i, v8::Local<v8::SharedArrayBuffer>::Cast(wrapper));
} else {
DOMArrayBuffer* arrayBuffer = DOMArrayBuffer::create(contents);
v8::Local<v8::Value> wrapper = toV8(arrayBuffer, creationContext, isolate);
DCHECK(wrapper->IsArrayBuffer());
m_deserializer.TransferArrayBuffer(i, v8::Local<v8::ArrayBuffer>::Cast(wrapper));
}
}
}
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8ScriptValueDeserializer_h
#define V8ScriptValueDeserializer_h
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/SerializedScriptValue.h"
#include "wtf/Allocator.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#include <v8.h>
namespace blink {
// Deserializes V8 values serialized using V8ScriptValueSerializer (or its
// predecessor, ScriptValueSerializer).
//
// Supports only basic JavaScript objects and core DOM types. Support for
// modules types is implemented in a subclass.
//
// A deserializer cannot be used multiple times; it is expected that its
// deserialize method will be invoked exactly once.
class V8ScriptValueDeserializer {
STACK_ALLOCATED();
WTF_MAKE_NONCOPYABLE(V8ScriptValueDeserializer);
public:
V8ScriptValueDeserializer(RefPtr<ScriptState>, RefPtr<SerializedScriptValue>);
v8::Local<v8::Value> deserialize();
protected:
uint32_t version() const { return m_version; }
private:
void transfer();
RefPtr<ScriptState> m_scriptState;
RefPtr<SerializedScriptValue> m_serializedScriptValue;
v8::ValueDeserializer m_deserializer;
// Set during deserialize after the header is read.
uint32_t m_version = 0;
#if DCHECK_IS_ON()
bool m_deserializeInvoked = false;
#endif
};
} // namespace blink
#endif // V8ScriptValueDeserializer_h
// Copyright 2016 The Chromium 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 "bindings/core/v8/serialization/V8ScriptValueSerializer.h"
#include "bindings/core/v8/ToV8.h"
#include "core/dom/DOMArrayBufferBase.h"
#include "platform/RuntimeEnabledFeatures.h"
namespace blink {
V8ScriptValueSerializer::V8ScriptValueSerializer(RefPtr<ScriptState> scriptState)
: m_scriptState(std::move(scriptState))
, m_serializedScriptValue(SerializedScriptValue::create())
, m_serializer(m_scriptState->isolate())
{
DCHECK(RuntimeEnabledFeatures::v8BasedStructuredCloneEnabled());
}
RefPtr<SerializedScriptValue> V8ScriptValueSerializer::serialize(v8::Local<v8::Value> value, Transferables* transferables, ExceptionState& exceptionState)
{
#if DCHECK_IS_ON()
DCHECK(!m_serializeInvoked);
m_serializeInvoked = true;
#endif
DCHECK(m_serializedScriptValue);
ScriptState::Scope scope(m_scriptState.get());
// Prepare to transfer the provided transferables.
transfer(transferables, exceptionState);
if (exceptionState.hadException()) {
return nullptr;
}
// Serialize the value and handle errors.
v8::TryCatch tryCatch(m_scriptState->isolate());
m_serializer.WriteHeader();
bool wroteValue;
if (!m_serializer.WriteValue(m_scriptState->context(), value).To(&wroteValue)) {
DCHECK(tryCatch.HasCaught());
exceptionState.rethrowV8Exception(tryCatch.Exception());
return nullptr;
}
if (!wroteValue) {
DCHECK(!tryCatch.HasCaught());
exceptionState.throwDOMException(DataCloneError, "An object could not be cloned.");
return nullptr;
}
// Finalize the results.
std::vector<uint8_t> buffer = m_serializer.ReleaseBuffer();
// Currently, the output must be padded to a multiple of two bytes.
// TODO(jbroman): Remove this old conversion to WTF::String.
if (buffer.size() % 2)
buffer.push_back(0);
m_serializedScriptValue->setData(
String(reinterpret_cast<const UChar*>(&buffer[0]), buffer.size() / 2));
return std::move(m_serializedScriptValue);
}
void V8ScriptValueSerializer::transfer(Transferables* transferables, ExceptionState& exceptionState)
{
if (!transferables)
return;
v8::Isolate* isolate = m_scriptState->isolate();
v8::Local<v8::Context> context = m_scriptState->context();
// Transfer array buffers.
m_serializedScriptValue->transferArrayBuffers(isolate, transferables->arrayBuffers, exceptionState);
if (exceptionState.hadException())
return;
for (uint32_t i = 0; i < transferables->arrayBuffers.size(); i++) {
DOMArrayBufferBase* arrayBuffer = transferables->arrayBuffers[i].get();
v8::Local<v8::Value> wrapper = toV8(arrayBuffer, context->Global(), isolate);
if (wrapper->IsArrayBuffer()) {
m_serializer.TransferArrayBuffer(
i, v8::Local<v8::ArrayBuffer>::Cast(wrapper));
} else if (wrapper->IsSharedArrayBuffer()) {
m_serializer.TransferSharedArrayBuffer(
i, v8::Local<v8::SharedArrayBuffer>::Cast(wrapper));
} else {
NOTREACHED() << "Unknown type of array buffer in transfer list.";
}
}
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8ScriptValueSerializer_h
#define V8ScriptValueSerializer_h
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/SerializedScriptValue.h"
#include "wtf/Allocator.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#include <v8.h>
namespace blink {
class Transferables;
// Serializes V8 values according to the HTML structured clone algorithm:
// https://html.spec.whatwg.org/multipage/infrastructure.html#structured-clone
//
// Supports only basic JavaScript objects and core DOM types. Support for
// modules types is implemented in a subclass.
//
// A serializer cannot be used multiple times; it is expected that its serialize
// method will be invoked exactly once.
class V8ScriptValueSerializer {
STACK_ALLOCATED();
WTF_MAKE_NONCOPYABLE(V8ScriptValueSerializer);
public:
explicit V8ScriptValueSerializer(RefPtr<ScriptState>);
RefPtr<SerializedScriptValue> serialize(v8::Local<v8::Value>, Transferables*, ExceptionState&);
private:
void transfer(Transferables*, ExceptionState&);
RefPtr<ScriptState> m_scriptState;
RefPtr<SerializedScriptValue> m_serializedScriptValue;
v8::ValueSerializer m_serializer;
#if DCHECK_IS_ON()
bool m_serializeInvoked = false;
#endif
};
} // namespace blink
#endif // V8ScriptValueSerializer_h
......@@ -189,6 +189,10 @@
'WorkerOrWorkletScriptController.h',
'WrapperTypeInfo.cpp',
'WrapperTypeInfo.h',
'serialization/V8ScriptValueDeserializer.cpp',
'serialization/V8ScriptValueDeserializer.h',
'serialization/V8ScriptValueSerializer.cpp',
'serialization/V8ScriptValueSerializer.h',
],
'bindings_core_v8_unittest_files': [
'DocumentWriteEvaluatorTest.cpp',
......
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