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