1// Copyright 2016 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 V8_VALUE_SERIALIZER_H_
6#define V8_VALUE_SERIALIZER_H_
7
8#include <cstdint>
9#include <vector>
10
11#include "include/v8.h"
12#include "src/base/compiler-specific.h"
13#include "src/base/macros.h"
14#include "src/identity-map.h"
15#include "src/maybe-handles.h"
16#include "src/message-template.h"
17#include "src/vector.h"
18#include "src/zone/zone.h"
19
20namespace v8 {
21namespace internal {
22
23class BigInt;
24class HeapNumber;
25class Isolate;
26class JSArrayBuffer;
27class JSArrayBufferView;
28class JSDate;
29class JSMap;
30class JSRegExp;
31class JSSet;
32class JSValue;
33class MutableHeapNumber;
34class Object;
35class Oddball;
36class Smi;
37class WasmMemoryObject;
38class WasmModuleObject;
39
40enum class SerializationTag : uint8_t;
41
42/**
43 * Writes V8 objects in a binary format that allows the objects to be cloned
44 * according to the HTML structured clone algorithm.
45 *
46 * Format is based on Blink's previous serialization logic.
47 */
48class ValueSerializer {
49 public:
50 ValueSerializer(Isolate* isolate, v8::ValueSerializer::Delegate* delegate);
51 ~ValueSerializer();
52
53 /*
54 * Writes out a header, which includes the format version.
55 */
56 void WriteHeader();
57
58 /*
59 * Serializes a V8 object into the buffer.
60 */
61 Maybe<bool> WriteObject(Handle<Object> object) V8_WARN_UNUSED_RESULT;
62
63 /*
64 * Returns the buffer, allocated via the delegate, and its size.
65 * Caller assumes ownership of the buffer.
66 */
67 std::pair<uint8_t*, size_t> Release();
68
69 /*
70 * Marks an ArrayBuffer as havings its contents transferred out of band.
71 * Pass the corresponding JSArrayBuffer in the deserializing context to
72 * ValueDeserializer::TransferArrayBuffer.
73 */
74 void TransferArrayBuffer(uint32_t transfer_id,
75 Handle<JSArrayBuffer> array_buffer);
76
77 /*
78 * Publicly exposed wire format writing methods.
79 * These are intended for use within the delegate's WriteHostObject method.
80 */
81 void WriteUint32(uint32_t value);
82 void WriteUint64(uint64_t value);
83 void WriteRawBytes(const void* source, size_t length);
84 void WriteDouble(double value);
85
86 /*
87 * Indicate whether to treat ArrayBufferView objects as host objects,
88 * i.e. pass them to Delegate::WriteHostObject. This should not be
89 * called when no Delegate was passed.
90 *
91 * The default is not to treat ArrayBufferViews as host objects.
92 */
93 void SetTreatArrayBufferViewsAsHostObjects(bool mode);
94
95 private:
96 // Managing allocations of the internal buffer.
97 Maybe<bool> ExpandBuffer(size_t required_capacity);
98
99 // Writing the wire format.
100 void WriteTag(SerializationTag tag);
101 template <typename T>
102 void WriteVarint(T value);
103 template <typename T>
104 void WriteZigZag(T value);
105 void WriteOneByteString(Vector<const uint8_t> chars);
106 void WriteTwoByteString(Vector<const uc16> chars);
107 void WriteBigIntContents(BigInt bigint);
108 Maybe<uint8_t*> ReserveRawBytes(size_t bytes);
109
110 // Writing V8 objects of various kinds.
111 void WriteOddball(Oddball oddball);
112 void WriteSmi(Smi smi);
113 void WriteHeapNumber(HeapNumber number);
114 void WriteMutableHeapNumber(MutableHeapNumber number);
115 void WriteBigInt(BigInt bigint);
116 void WriteString(Handle<String> string);
117 Maybe<bool> WriteJSReceiver(Handle<JSReceiver> receiver)
118 V8_WARN_UNUSED_RESULT;
119 Maybe<bool> WriteJSObject(Handle<JSObject> object) V8_WARN_UNUSED_RESULT;
120 Maybe<bool> WriteJSObjectSlow(Handle<JSObject> object) V8_WARN_UNUSED_RESULT;
121 Maybe<bool> WriteJSArray(Handle<JSArray> array) V8_WARN_UNUSED_RESULT;
122 void WriteJSDate(JSDate date);
123 Maybe<bool> WriteJSValue(Handle<JSValue> value) V8_WARN_UNUSED_RESULT;
124 void WriteJSRegExp(JSRegExp regexp);
125 Maybe<bool> WriteJSMap(Handle<JSMap> map) V8_WARN_UNUSED_RESULT;
126 Maybe<bool> WriteJSSet(Handle<JSSet> map) V8_WARN_UNUSED_RESULT;
127 Maybe<bool> WriteJSArrayBuffer(Handle<JSArrayBuffer> array_buffer)
128 V8_WARN_UNUSED_RESULT;
129 Maybe<bool> WriteJSArrayBufferView(JSArrayBufferView array_buffer);
130 Maybe<bool> WriteWasmModule(Handle<WasmModuleObject> object)
131 V8_WARN_UNUSED_RESULT;
132 Maybe<bool> WriteWasmMemory(Handle<WasmMemoryObject> object)
133 V8_WARN_UNUSED_RESULT;
134 Maybe<bool> WriteHostObject(Handle<JSObject> object) V8_WARN_UNUSED_RESULT;
135
136 /*
137 * Reads the specified keys from the object and writes key-value pairs to the
138 * buffer. Returns the number of keys actually written, which may be smaller
139 * if some keys are not own properties when accessed.
140 */
141 Maybe<uint32_t> WriteJSObjectPropertiesSlow(
142 Handle<JSObject> object, Handle<FixedArray> keys) V8_WARN_UNUSED_RESULT;
143
144 /*
145 * Asks the delegate to handle an error that occurred during data cloning, by
146 * throwing an exception appropriate for the host.
147 */
148 void ThrowDataCloneError(MessageTemplate template_index);
149 V8_NOINLINE void ThrowDataCloneError(MessageTemplate template_index,
150 Handle<Object> arg0);
151
152 Maybe<bool> ThrowIfOutOfMemory();
153
154 Isolate* const isolate_;
155 v8::ValueSerializer::Delegate* const delegate_;
156 uint8_t* buffer_ = nullptr;
157 size_t buffer_size_ = 0;
158 size_t buffer_capacity_ = 0;
159 bool treat_array_buffer_views_as_host_objects_ = false;
160 bool out_of_memory_ = false;
161 Zone zone_;
162
163 // To avoid extra lookups in the identity map, ID+1 is actually stored in the
164 // map (checking if the used identity is zero is the fast way of checking if
165 // the entry is new).
166 IdentityMap<uint32_t, ZoneAllocationPolicy> id_map_;
167 uint32_t next_id_ = 0;
168
169 // A similar map, for transferred array buffers.
170 IdentityMap<uint32_t, ZoneAllocationPolicy> array_buffer_transfer_map_;
171
172 DISALLOW_COPY_AND_ASSIGN(ValueSerializer);
173};
174
175/*
176 * Deserializes values from data written with ValueSerializer, or a compatible
177 * implementation.
178 */
179class ValueDeserializer {
180 public:
181 ValueDeserializer(Isolate* isolate, Vector<const uint8_t> data,
182 v8::ValueDeserializer::Delegate* delegate);
183 ~ValueDeserializer();
184
185 /*
186 * Runs version detection logic, which may fail if the format is invalid.
187 */
188 Maybe<bool> ReadHeader() V8_WARN_UNUSED_RESULT;
189
190 /*
191 * Reads the underlying wire format version. Likely mostly to be useful to
192 * legacy code reading old wire format versions. Must be called after
193 * ReadHeader.
194 */
195 uint32_t GetWireFormatVersion() const { return version_; }
196
197 /*
198 * Deserializes a V8 object from the buffer.
199 */
200 MaybeHandle<Object> ReadObject() V8_WARN_UNUSED_RESULT;
201
202 /*
203 * Reads an object, consuming the entire buffer.
204 *
205 * This is required for the legacy "version 0" format, which did not allow
206 * reference deduplication, and instead relied on a "stack" model for
207 * deserializing, with the contents of objects and arrays provided first.
208 */
209 MaybeHandle<Object> ReadObjectUsingEntireBufferForLegacyFormat()
210 V8_WARN_UNUSED_RESULT;
211
212 /*
213 * Accepts the array buffer corresponding to the one passed previously to
214 * ValueSerializer::TransferArrayBuffer.
215 */
216 void TransferArrayBuffer(uint32_t transfer_id,
217 Handle<JSArrayBuffer> array_buffer);
218
219 /*
220 * Publicly exposed wire format writing methods.
221 * These are intended for use within the delegate's WriteHostObject method.
222 */
223 bool ReadUint32(uint32_t* value) V8_WARN_UNUSED_RESULT;
224 bool ReadUint64(uint64_t* value) V8_WARN_UNUSED_RESULT;
225 bool ReadDouble(double* value) V8_WARN_UNUSED_RESULT;
226 bool ReadRawBytes(size_t length, const void** data) V8_WARN_UNUSED_RESULT;
227 void set_expect_inline_wasm(bool expect_inline_wasm) {
228 expect_inline_wasm_ = expect_inline_wasm;
229 }
230
231 private:
232 // Reading the wire format.
233 Maybe<SerializationTag> PeekTag() const V8_WARN_UNUSED_RESULT;
234 void ConsumeTag(SerializationTag peeked_tag);
235 Maybe<SerializationTag> ReadTag() V8_WARN_UNUSED_RESULT;
236 template <typename T>
237 Maybe<T> ReadVarint() V8_WARN_UNUSED_RESULT;
238 template <typename T>
239 Maybe<T> ReadZigZag() V8_WARN_UNUSED_RESULT;
240 Maybe<double> ReadDouble() V8_WARN_UNUSED_RESULT;
241 Maybe<Vector<const uint8_t>> ReadRawBytes(int size) V8_WARN_UNUSED_RESULT;
242 bool expect_inline_wasm() const { return expect_inline_wasm_; }
243
244 // Reads a string if it matches the one provided.
245 // Returns true if this was the case. Otherwise, nothing is consumed.
246 bool ReadExpectedString(Handle<String> expected) V8_WARN_UNUSED_RESULT;
247
248 // Like ReadObject, but skips logic for special cases in simulating the
249 // "stack machine".
250 MaybeHandle<Object> ReadObjectInternal() V8_WARN_UNUSED_RESULT;
251
252 // Reads a string intended to be part of a more complicated object.
253 // Before v12, these are UTF-8 strings. After, they can be any encoding
254 // permissible for a string (with the relevant tag).
255 MaybeHandle<String> ReadString() V8_WARN_UNUSED_RESULT;
256
257 // Reading V8 objects of specific kinds.
258 // The tag is assumed to have already been read.
259 MaybeHandle<BigInt> ReadBigInt() V8_WARN_UNUSED_RESULT;
260 MaybeHandle<String> ReadUtf8String() V8_WARN_UNUSED_RESULT;
261 MaybeHandle<String> ReadOneByteString() V8_WARN_UNUSED_RESULT;
262 MaybeHandle<String> ReadTwoByteString() V8_WARN_UNUSED_RESULT;
263 MaybeHandle<JSObject> ReadJSObject() V8_WARN_UNUSED_RESULT;
264 MaybeHandle<JSArray> ReadSparseJSArray() V8_WARN_UNUSED_RESULT;
265 MaybeHandle<JSArray> ReadDenseJSArray() V8_WARN_UNUSED_RESULT;
266 MaybeHandle<JSDate> ReadJSDate() V8_WARN_UNUSED_RESULT;
267 MaybeHandle<JSValue> ReadJSValue(SerializationTag tag) V8_WARN_UNUSED_RESULT;
268 MaybeHandle<JSRegExp> ReadJSRegExp() V8_WARN_UNUSED_RESULT;
269 MaybeHandle<JSMap> ReadJSMap() V8_WARN_UNUSED_RESULT;
270 MaybeHandle<JSSet> ReadJSSet() V8_WARN_UNUSED_RESULT;
271 MaybeHandle<JSArrayBuffer> ReadJSArrayBuffer(bool is_shared)
272 V8_WARN_UNUSED_RESULT;
273 MaybeHandle<JSArrayBuffer> ReadTransferredJSArrayBuffer()
274 V8_WARN_UNUSED_RESULT;
275 MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView(
276 Handle<JSArrayBuffer> buffer) V8_WARN_UNUSED_RESULT;
277 MaybeHandle<JSObject> ReadWasmModule() V8_WARN_UNUSED_RESULT;
278 MaybeHandle<JSObject> ReadWasmModuleTransfer() V8_WARN_UNUSED_RESULT;
279 MaybeHandle<WasmMemoryObject> ReadWasmMemory() V8_WARN_UNUSED_RESULT;
280 MaybeHandle<JSObject> ReadHostObject() V8_WARN_UNUSED_RESULT;
281
282 /*
283 * Reads key-value pairs into the object until the specified end tag is
284 * encountered. If successful, returns the number of properties read.
285 */
286 Maybe<uint32_t> ReadJSObjectProperties(Handle<JSObject> object,
287 SerializationTag end_tag,
288 bool can_use_transitions);
289
290 // Manipulating the map from IDs to reified objects.
291 bool HasObjectWithID(uint32_t id);
292 MaybeHandle<JSReceiver> GetObjectWithID(uint32_t id);
293 void AddObjectWithID(uint32_t id, Handle<JSReceiver> object);
294
295 Isolate* const isolate_;
296 v8::ValueDeserializer::Delegate* const delegate_;
297 const uint8_t* position_;
298 const uint8_t* const end_;
299 AllocationType allocation_;
300 uint32_t version_ = 0;
301 uint32_t next_id_ = 0;
302 bool expect_inline_wasm_ = false;
303
304 // Always global handles.
305 Handle<FixedArray> id_map_;
306 MaybeHandle<SimpleNumberDictionary> array_buffer_transfer_map_;
307
308 DISALLOW_COPY_AND_ASSIGN(ValueDeserializer);
309};
310
311} // namespace internal
312} // namespace v8
313
314#endif // V8_VALUE_SERIALIZER_H_
315