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