1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_V8_VALUE_SERIALIZER_H_
6#define INCLUDE_V8_VALUE_SERIALIZER_H_
7
8#include <stddef.h>
9#include <stdint.h>
10
11#include <memory>
12#include <utility>
13
14#include "v8-local-handle.h"  // NOLINT(build/include_directory)
15#include "v8-maybe.h"         // NOLINT(build/include_directory)
16#include "v8config.h"         // NOLINT(build/include_directory)
17
18namespace v8 {
19
20class ArrayBuffer;
21class Isolate;
22class Object;
23class SharedArrayBuffer;
24class String;
25class WasmModuleObject;
26class Value;
27
28namespace internal {
29struct ScriptStreamingData;
30class SharedObjectConveyorHandles;
31class ValueDeserializer;
32class ValueSerializer;
33}  // namespace internal
34
35/**
36 * A move-only class for managing the lifetime of shared value conveyors used
37 * by V8 to keep JS shared values alive in transit when serialized.
38 *
39 * This class is not directly constructible and is always passed to a
40 * ValueSerializer::Delegate via ValueSerializer::SetSharedValueConveyor.
41 *
42 * The embedder must not destruct the SharedValueConveyor until the associated
43 * serialized data will no longer be deserialized.
44 */
45class V8_EXPORT SharedValueConveyor final {
46 public:
47  SharedValueConveyor(SharedValueConveyor&&) noexcept;
48  ~SharedValueConveyor();
49
50  SharedValueConveyor& operator=(SharedValueConveyor&&) noexcept;
51
52 private:
53  friend class internal::ValueSerializer;
54  friend class internal::ValueDeserializer;
55
56  explicit SharedValueConveyor(Isolate* isolate);
57
58  std::unique_ptr<internal::SharedObjectConveyorHandles> private_;
59};
60
61/**
62 * Value serialization compatible with the HTML structured clone algorithm.
63 * The format is backward-compatible (i.e. safe to store to disk).
64 */
65class V8_EXPORT ValueSerializer {
66 public:
67  class V8_EXPORT Delegate {
68   public:
69    virtual ~Delegate() = default;
70
71    /**
72     * Handles the case where a DataCloneError would be thrown in the structured
73     * clone spec. Other V8 embedders may throw some other appropriate exception
74     * type.
75     */
76    virtual void ThrowDataCloneError(Local<String> message) = 0;
77
78    /**
79     * The embedder overrides this method to enable custom host object filter
80     * with Delegate::IsHostObject.
81     *
82     * This method is called at most once per serializer.
83     */
84    virtual bool HasCustomHostObject(Isolate* isolate);
85
86    /**
87     * The embedder overrides this method to determine if an JS object is a
88     * host object and needs to be serialized by the host.
89     */
90    virtual Maybe<bool> IsHostObject(Isolate* isolate, Local<Object> object);
91
92    /**
93     * The embedder overrides this method to write some kind of host object, if
94     * possible. If not, a suitable exception should be thrown and
95     * Nothing<bool>() returned.
96     */
97    virtual Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object);
98
99    /**
100     * Called when the ValueSerializer is going to serialize a
101     * SharedArrayBuffer object. The embedder must return an ID for the
102     * object, using the same ID if this SharedArrayBuffer has already been
103     * serialized in this buffer. When deserializing, this ID will be passed to
104     * ValueDeserializer::GetSharedArrayBufferFromId as |clone_id|.
105     *
106     * If the object cannot be serialized, an
107     * exception should be thrown and Nothing<uint32_t>() returned.
108     */
109    virtual Maybe<uint32_t> GetSharedArrayBufferId(
110        Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer);
111
112    virtual Maybe<uint32_t> GetWasmModuleTransferId(
113        Isolate* isolate, Local<WasmModuleObject> module);
114
115    /**
116     * Called when the first shared value is serialized. All subsequent shared
117     * values will use the same conveyor.
118     *
119     * The embedder must ensure the lifetime of the conveyor matches the
120     * lifetime of the serialized data.
121     *
122     * If the embedder supports serializing shared values, this method should
123     * return true. Otherwise the embedder should throw an exception and return
124     * false.
125     *
126     * This method is called at most once per serializer.
127     */
128    virtual bool AdoptSharedValueConveyor(Isolate* isolate,
129                                          SharedValueConveyor&& conveyor);
130
131    /**
132     * Allocates memory for the buffer of at least the size provided. The actual
133     * size (which may be greater or equal) is written to |actual_size|. If no
134     * buffer has been allocated yet, nullptr will be provided.
135     *
136     * If the memory cannot be allocated, nullptr should be returned.
137     * |actual_size| will be ignored. It is assumed that |old_buffer| is still
138     * valid in this case and has not been modified.
139     *
140     * The default implementation uses the stdlib's `realloc()` function.
141     */
142    virtual void* ReallocateBufferMemory(void* old_buffer, size_t size,
143                                         size_t* actual_size);
144
145    /**
146     * Frees a buffer allocated with |ReallocateBufferMemory|.
147     *
148     * The default implementation uses the stdlib's `free()` function.
149     */
150    virtual void FreeBufferMemory(void* buffer);
151  };
152
153  explicit ValueSerializer(Isolate* isolate);
154  ValueSerializer(Isolate* isolate, Delegate* delegate);
155  ~ValueSerializer();
156
157  /**
158   * Writes out a header, which includes the format version.
159   */
160  void WriteHeader();
161
162  /**
163   * Serializes a JavaScript value into the buffer.
164   */
165  V8_WARN_UNUSED_RESULT Maybe<bool> WriteValue(Local<Context> context,
166                                               Local<Value> value);
167
168  /**
169   * Returns the stored data (allocated using the delegate's
170   * ReallocateBufferMemory) and its size. This serializer should not be used
171   * once the buffer is released. The contents are undefined if a previous write
172   * has failed. Ownership of the buffer is transferred to the caller.
173   */
174  V8_WARN_UNUSED_RESULT std::pair<uint8_t*, size_t> Release();
175
176  /**
177   * Marks an ArrayBuffer as havings its contents transferred out of band.
178   * Pass the corresponding ArrayBuffer in the deserializing context to
179   * ValueDeserializer::TransferArrayBuffer.
180   */
181  void TransferArrayBuffer(uint32_t transfer_id,
182                           Local<ArrayBuffer> array_buffer);
183
184  /**
185   * Indicate whether to treat ArrayBufferView objects as host objects,
186   * i.e. pass them to Delegate::WriteHostObject. This should not be
187   * called when no Delegate was passed.
188   *
189   * The default is not to treat ArrayBufferViews as host objects.
190   */
191  void SetTreatArrayBufferViewsAsHostObjects(bool mode);
192
193  /**
194   * Write raw data in various common formats to the buffer.
195   * Note that integer types are written in base-128 varint format, not with a
196   * binary copy. For use during an override of Delegate::WriteHostObject.
197   */
198  void WriteUint32(uint32_t value);
199  void WriteUint64(uint64_t value);
200  void WriteDouble(double value);
201  void WriteRawBytes(const void* source, size_t length);
202
203  ValueSerializer(const ValueSerializer&) = delete;
204  void operator=(const ValueSerializer&) = delete;
205
206 private:
207  struct PrivateData;
208  PrivateData* private_;
209};
210
211/**
212 * Deserializes values from data written with ValueSerializer, or a compatible
213 * implementation.
214 */
215class V8_EXPORT ValueDeserializer {
216 public:
217  class V8_EXPORT Delegate {
218   public:
219    virtual ~Delegate() = default;
220
221    /**
222     * The embedder overrides this method to read some kind of host object, if
223     * possible. If not, a suitable exception should be thrown and
224     * MaybeLocal<Object>() returned.
225     */
226    virtual MaybeLocal<Object> ReadHostObject(Isolate* isolate);
227
228    /**
229     * Get a WasmModuleObject given a transfer_id previously provided
230     * by ValueSerializer::Delegate::GetWasmModuleTransferId
231     */
232    virtual MaybeLocal<WasmModuleObject> GetWasmModuleFromId(
233        Isolate* isolate, uint32_t transfer_id);
234
235    /**
236     * Get a SharedArrayBuffer given a clone_id previously provided
237     * by ValueSerializer::Delegate::GetSharedArrayBufferId
238     */
239    virtual MaybeLocal<SharedArrayBuffer> GetSharedArrayBufferFromId(
240        Isolate* isolate, uint32_t clone_id);
241
242    /**
243     * Get the SharedValueConveyor previously provided by
244     * ValueSerializer::Delegate::AdoptSharedValueConveyor.
245     */
246    virtual const SharedValueConveyor* GetSharedValueConveyor(Isolate* isolate);
247  };
248
249  ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size);
250  ValueDeserializer(Isolate* isolate, const uint8_t* data, size_t size,
251                    Delegate* delegate);
252  ~ValueDeserializer();
253
254  /**
255   * Reads and validates a header (including the format version).
256   * May, for example, reject an invalid or unsupported wire format.
257   */
258  V8_WARN_UNUSED_RESULT Maybe<bool> ReadHeader(Local<Context> context);
259
260  /**
261   * Deserializes a JavaScript value from the buffer.
262   */
263  V8_WARN_UNUSED_RESULT MaybeLocal<Value> ReadValue(Local<Context> context);
264
265  /**
266   * Accepts the array buffer corresponding to the one passed previously to
267   * ValueSerializer::TransferArrayBuffer.
268   */
269  void TransferArrayBuffer(uint32_t transfer_id,
270                           Local<ArrayBuffer> array_buffer);
271
272  /**
273   * Similar to TransferArrayBuffer, but for SharedArrayBuffer.
274   * The id is not necessarily in the same namespace as unshared ArrayBuffer
275   * objects.
276   */
277  void TransferSharedArrayBuffer(uint32_t id,
278                                 Local<SharedArrayBuffer> shared_array_buffer);
279
280  /**
281   * Must be called before ReadHeader to enable support for reading the legacy
282   * wire format (i.e., which predates this being shipped).
283   *
284   * Don't use this unless you need to read data written by previous versions of
285   * blink::ScriptValueSerializer.
286   */
287  void SetSupportsLegacyWireFormat(bool supports_legacy_wire_format);
288
289  /**
290   * Reads the underlying wire format version. Likely mostly to be useful to
291   * legacy code reading old wire format versions. Must be called after
292   * ReadHeader.
293   */
294  uint32_t GetWireFormatVersion() const;
295
296  /**
297   * Reads raw data in various common formats to the buffer.
298   * Note that integer types are read in base-128 varint format, not with a
299   * binary copy. For use during an override of Delegate::ReadHostObject.
300   */
301  V8_WARN_UNUSED_RESULT bool ReadUint32(uint32_t* value);
302  V8_WARN_UNUSED_RESULT bool ReadUint64(uint64_t* value);
303  V8_WARN_UNUSED_RESULT bool ReadDouble(double* value);
304  V8_WARN_UNUSED_RESULT bool ReadRawBytes(size_t length, const void** data);
305
306  ValueDeserializer(const ValueDeserializer&) = delete;
307  void operator=(const ValueDeserializer&) = delete;
308
309 private:
310  struct PrivateData;
311  PrivateData* private_;
312};
313
314}  // namespace v8
315
316#endif  // INCLUDE_V8_VALUE_SERIALIZER_H_
317