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