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