7524089264
Shared values need to be kept alive while being conveyed across threads (i.e. by postMessage). Currently they are meant to be conveyed through the serializer/deserializer by the embedder via API. This both clunky and the embedder has no good choice for what to do, because the most natural choice is v8::Global and it is not designed to be threadsafe. This CL removes the API and transparently handles conveying shared values by using a wrapper around PersistentHandles called SharedValueConveyors. Any isolate can own the conveyor provided it outlives the receipt of the message by the receiving isolate. For simpler lifetime management, the shared isolate currently owns all conveyors. Bug: v8:12547 Change-Id: I8f71b2faa0f8a1973f8b97ffccf4f5ad230f4e16 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3857453 Reviewed-by: Jakob Linke <jgruber@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#82795}
261 lines
8.6 KiB
C++
261 lines
8.6 KiB
C++
// Copyright 2021 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.
|
|
|
|
#ifndef INCLUDE_V8_VALUE_SERIALIZER_H_
|
|
#define INCLUDE_V8_VALUE_SERIALIZER_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <utility>
|
|
|
|
#include "v8-local-handle.h" // NOLINT(build/include_directory)
|
|
#include "v8-maybe.h" // NOLINT(build/include_directory)
|
|
#include "v8config.h" // NOLINT(build/include_directory)
|
|
|
|
namespace v8 {
|
|
|
|
class ArrayBuffer;
|
|
class Isolate;
|
|
class Object;
|
|
class SharedArrayBuffer;
|
|
class String;
|
|
class WasmModuleObject;
|
|
class Value;
|
|
|
|
namespace internal {
|
|
struct ScriptStreamingData;
|
|
} // namespace internal
|
|
|
|
/**
|
|
* Value serialization compatible with the HTML structured clone algorithm.
|
|
* The format is backward-compatible (i.e. safe to store to disk).
|
|
*/
|
|
class V8_EXPORT ValueSerializer {
|
|
public:
|
|
class V8_EXPORT Delegate {
|
|
public:
|
|
virtual ~Delegate() = default;
|
|
|
|
/**
|
|
* Handles the case where a DataCloneError would be thrown in the structured
|
|
* clone spec. Other V8 embedders may throw some other appropriate exception
|
|
* 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);
|
|
|
|
/**
|
|
* Called when the ValueSerializer is going to serialize a
|
|
* SharedArrayBuffer object. The embedder must return an ID for the
|
|
* object, using the same ID if this SharedArrayBuffer has already been
|
|
* serialized in this buffer. When deserializing, this ID will be passed to
|
|
* ValueDeserializer::GetSharedArrayBufferFromId as |clone_id|.
|
|
*
|
|
* If the object cannot be serialized, an
|
|
* exception should be thrown and Nothing<uint32_t>() returned.
|
|
*/
|
|
virtual Maybe<uint32_t> GetSharedArrayBufferId(
|
|
Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer);
|
|
|
|
virtual Maybe<uint32_t> GetWasmModuleTransferId(
|
|
Isolate* isolate, Local<WasmModuleObject> module);
|
|
|
|
/**
|
|
* Returns whether conveying shared values are supported.
|
|
*/
|
|
virtual bool SupportsSharedValues() const;
|
|
|
|
/**
|
|
* Allocates memory for the buffer of at least the size provided. The actual
|
|
* size (which may be greater or equal) is written to |actual_size|. If no
|
|
* buffer has been allocated yet, nullptr will be provided.
|
|
*
|
|
* If the memory cannot be allocated, nullptr should be returned.
|
|
* |actual_size| will be ignored. It is assumed that |old_buffer| is still
|
|
* valid in this case and has not been modified.
|
|
*
|
|
* The default implementation uses the stdlib's `realloc()` function.
|
|
*/
|
|
virtual void* ReallocateBufferMemory(void* old_buffer, size_t size,
|
|
size_t* actual_size);
|
|
|
|
/**
|
|
* Frees a buffer allocated with |ReallocateBufferMemory|.
|
|
*
|
|
* The default implementation uses the stdlib's `free()` function.
|
|
*/
|
|
virtual void FreeBufferMemory(void* buffer);
|
|
};
|
|
|
|
explicit ValueSerializer(Isolate* isolate);
|
|
ValueSerializer(Isolate* isolate, Delegate* delegate);
|
|
~ValueSerializer();
|
|
|
|
/**
|
|
* Writes out a header, which includes the format version.
|
|
*/
|
|
void WriteHeader();
|
|
|
|
/**
|
|
* Serializes a JavaScript value into the buffer.
|
|
*/
|
|
V8_WARN_UNUSED_RESULT Maybe<bool> WriteValue(Local<Context> context,
|
|
Local<Value> value);
|
|
|
|
/**
|
|
* Returns the stored data (allocated using the delegate's
|
|
* ReallocateBufferMemory) and its size. This serializer should not be used
|
|
* once the buffer is released. The contents are undefined if a previous write
|
|
* has failed. Ownership of the buffer is transferred to the caller.
|
|
*/
|
|
V8_WARN_UNUSED_RESULT std::pair<uint8_t*, size_t> Release();
|
|
|
|
/**
|
|
* Marks an ArrayBuffer as havings its contents transferred out of band.
|
|
* Pass the corresponding ArrayBuffer in the deserializing context to
|
|
* ValueDeserializer::TransferArrayBuffer.
|
|
*/
|
|
void TransferArrayBuffer(uint32_t transfer_id,
|
|
Local<ArrayBuffer> array_buffer);
|
|
|
|
/**
|
|
* Indicate whether to treat ArrayBufferView objects as host objects,
|
|
* i.e. pass them to Delegate::WriteHostObject. This should not be
|
|
* called when no Delegate was passed.
|
|
*
|
|
* The default is not to treat ArrayBufferViews as host objects.
|
|
*/
|
|
void SetTreatArrayBufferViewsAsHostObjects(bool mode);
|
|
|
|
/**
|
|
* 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 WriteDouble(double value);
|
|
void WriteRawBytes(const void* source, size_t length);
|
|
|
|
ValueSerializer(const ValueSerializer&) = delete;
|
|
void operator=(const ValueSerializer&) = delete;
|
|
|
|
private:
|
|
struct PrivateData;
|
|
PrivateData* private_;
|
|
};
|
|
|
|
/**
|
|
* Deserializes values from data written with ValueSerializer, or a compatible
|
|
* implementation.
|
|
*/
|
|
class V8_EXPORT ValueDeserializer {
|
|
public:
|
|
class V8_EXPORT Delegate {
|
|
public:
|
|
virtual ~Delegate() = default;
|
|
|
|
/**
|
|
* 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);
|
|
|
|
/**
|
|
* Get a WasmModuleObject given a transfer_id previously provided
|
|
* by ValueSerializer::Delegate::GetWasmModuleTransferId
|
|
*/
|
|
virtual MaybeLocal<WasmModuleObject> GetWasmModuleFromId(
|
|
Isolate* isolate, uint32_t transfer_id);
|
|
|
|
/**
|
|
* Get a SharedArrayBuffer given a clone_id previously provided
|
|
* by ValueSerializer::Delegate::GetSharedArrayBufferId
|
|
*/
|
|
virtual MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
|
|
Isolate* isolate, uint32_t clone_id);
|
|
|
|
/**
|
|
* Returns whether conveying shared values are supported.
|
|
*/
|
|
virtual bool SupportsSharedValues() const;
|
|
};
|
|
|
|
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size);
|
|
ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size,
|
|
Delegate* delegate);
|
|
~ValueDeserializer();
|
|
|
|
/**
|
|
* Reads and validates a header (including the format version).
|
|
* May, for example, reject an invalid or unsupported wire format.
|
|
*/
|
|
V8_WARN_UNUSED_RESULT Maybe<bool> ReadHeader(Local<Context> context);
|
|
|
|
/**
|
|
* Deserializes a JavaScript value from the buffer.
|
|
*/
|
|
V8_WARN_UNUSED_RESULT MaybeLocal<Value> ReadValue(Local<Context> context);
|
|
|
|
/**
|
|
* Accepts the array buffer corresponding to the one passed previously to
|
|
* ValueSerializer::TransferArrayBuffer.
|
|
*/
|
|
void TransferArrayBuffer(uint32_t transfer_id,
|
|
Local<ArrayBuffer> array_buffer);
|
|
|
|
/**
|
|
* Similar to TransferArrayBuffer, but for SharedArrayBuffer.
|
|
* The id is not necessarily in the same namespace as unshared ArrayBuffer
|
|
* objects.
|
|
*/
|
|
void TransferSharedArrayBuffer(uint32_t id,
|
|
Local<SharedArrayBuffer> shared_array_buffer);
|
|
|
|
/**
|
|
* Must be called before ReadHeader to enable support for reading the legacy
|
|
* wire format (i.e., which predates this being shipped).
|
|
*
|
|
* Don't use this unless you need to read data written by previous versions of
|
|
* blink::ScriptValueSerializer.
|
|
*/
|
|
void SetSupportsLegacyWireFormat(bool supports_legacy_wire_format);
|
|
|
|
/**
|
|
* Reads the underlying wire format version. Likely mostly to be useful to
|
|
* legacy code reading old wire format versions. Must be called after
|
|
* ReadHeader.
|
|
*/
|
|
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 ReadDouble(double* value);
|
|
V8_WARN_UNUSED_RESULT bool ReadRawBytes(size_t length, const void** data);
|
|
|
|
ValueDeserializer(const ValueDeserializer&) = delete;
|
|
void operator=(const ValueDeserializer&) = delete;
|
|
|
|
private:
|
|
struct PrivateData;
|
|
PrivateData* private_;
|
|
};
|
|
|
|
} // namespace v8
|
|
|
|
#endif // INCLUDE_V8_VALUE_SERIALIZER_H_
|