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_SNAPSHOT_DESERIALIZER_H_ 6 #define V8_SNAPSHOT_DESERIALIZER_H_ 7 8 #include <utility> 9 #include <vector> 10 11 #include "src/base/macros.h" 12 #include "src/base/optional.h" 13 #include "src/common/globals.h" 14 #include "src/execution/local-isolate.h" 15 #include "src/objects/allocation-site.h" 16 #include "src/objects/api-callbacks.h" 17 #include "src/objects/backing-store.h" 18 #include "src/objects/code.h" 19 #include "src/objects/js-array.h" 20 #include "src/objects/map.h" 21 #include "src/objects/smi.h" 22 #include "src/objects/string-table.h" 23 #include "src/objects/string.h" 24 #include "src/snapshot/serializer-deserializer.h" 25 #include "src/snapshot/snapshot-source-sink.h" 26 27 namespace v8 { 28 namespace internal { 29 30 class HeapObject; 31 class Object; 32 33 // Used for platforms with embedded constant pools to trigger deserialization 34 // of objects found in code. 35 #if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \ 36 defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390) || \ 37 defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_RISCV64) || \ 38 V8_EMBEDDED_CONSTANT_POOL 39 #define V8_CODE_EMBEDS_OBJECT_POINTER 1 40 #else 41 #define V8_CODE_EMBEDS_OBJECT_POINTER 0 42 #endif 43 44 // A Deserializer reads a snapshot and reconstructs the Object graph it defines. 45 template <typename IsolateT> 46 class Deserializer : public SerializerDeserializer { 47 public: 48 ~Deserializer() override; 49 Deserializer(const Deserializer&) = delete; 50 Deserializer& operator=(const Deserializer&) = delete; 51 52 protected: 53 // Create a deserializer from a snapshot byte source. 54 Deserializer(IsolateT* isolate, base::Vector<const byte> payload, 55 uint32_t magic_number, bool deserializing_user_code, 56 bool can_rehash); 57 58 void DeserializeDeferredObjects(); 59 60 // Create Log events for newly deserialized objects. 61 void LogNewObjectEvents(); 62 void LogScriptEvents(Script script); 63 void LogNewMapEvents(); 64 65 // Descriptor arrays are deserialized as "strong", so that there is no risk of 66 // them getting trimmed during a partial deserialization. This method makes 67 // them "weak" again after deserialization completes. 68 void WeakenDescriptorArrays(); 69 70 // This returns the address of an object that has been described in the 71 // snapshot by object vector index. 72 Handle<HeapObject> GetBackReferencedObject(); 73 74 // Add an object to back an attached reference. The order to add objects must 75 // mirror the order they are added in the serializer. AddAttachedObject(Handle<HeapObject> attached_object)76 void AddAttachedObject(Handle<HeapObject> attached_object) { 77 attached_objects_.push_back(attached_object); 78 } 79 CheckNoArrayBufferBackingStores()80 void CheckNoArrayBufferBackingStores() { 81 CHECK_EQ(new_off_heap_array_buffers().size(), 0); 82 } 83 isolate()84 IsolateT* isolate() const { return isolate_; } 85 main_thread_isolate()86 Isolate* main_thread_isolate() const { return isolate_->AsIsolate(); } 87 source()88 SnapshotByteSource* source() { return &source_; } new_allocation_sites()89 const std::vector<Handle<AllocationSite>>& new_allocation_sites() const { 90 return new_allocation_sites_; 91 } new_code_objects()92 const std::vector<Handle<Code>>& new_code_objects() const { 93 return new_code_objects_; 94 } new_maps()95 const std::vector<Handle<Map>>& new_maps() const { return new_maps_; } accessor_infos()96 const std::vector<Handle<AccessorInfo>>& accessor_infos() const { 97 return accessor_infos_; 98 } call_handler_infos()99 const std::vector<Handle<CallHandlerInfo>>& call_handler_infos() const { 100 return call_handler_infos_; 101 } new_scripts()102 const std::vector<Handle<Script>>& new_scripts() const { 103 return new_scripts_; 104 } 105 new_off_heap_array_buffers()106 const std::vector<Handle<JSArrayBuffer>>& new_off_heap_array_buffers() const { 107 return new_off_heap_array_buffers_; 108 } 109 new_descriptor_arrays()110 const std::vector<Handle<DescriptorArray>>& new_descriptor_arrays() const { 111 return new_descriptor_arrays_; 112 } 113 backing_store(size_t i)114 std::shared_ptr<BackingStore> backing_store(size_t i) { 115 DCHECK_LT(i, backing_stores_.size()); 116 return backing_stores_[i]; 117 } 118 deserializing_user_code()119 bool deserializing_user_code() const { return deserializing_user_code_; } should_rehash()120 bool should_rehash() const { return should_rehash_; } 121 122 void Rehash(); 123 124 Handle<HeapObject> ReadObject(); 125 126 private: 127 friend class DeserializerRelocInfoVisitor; 128 // A circular queue of hot objects. This is added to in the same order as in 129 // Serializer::HotObjectsList, but this stores the objects as a vector of 130 // existing handles. This allows us to add Handles to the queue without having 131 // to create new handles. Note that this depends on those Handles staying 132 // valid as long as the HotObjectsList is alive. 133 class HotObjectsList { 134 public: 135 HotObjectsList() = default; 136 HotObjectsList(const HotObjectsList&) = delete; 137 HotObjectsList& operator=(const HotObjectsList&) = delete; 138 Add(Handle<HeapObject> object)139 void Add(Handle<HeapObject> object) { 140 circular_queue_[index_] = object; 141 index_ = (index_ + 1) & kSizeMask; 142 } 143 Get(int index)144 Handle<HeapObject> Get(int index) { 145 DCHECK(!circular_queue_[index].is_null()); 146 return circular_queue_[index]; 147 } 148 149 private: 150 static const int kSize = kHotObjectCount; 151 static const int kSizeMask = kSize - 1; 152 STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize)); 153 Handle<HeapObject> circular_queue_[kSize]; 154 int index_ = 0; 155 }; 156 157 void VisitRootPointers(Root root, const char* description, 158 FullObjectSlot start, FullObjectSlot end) override; 159 160 void Synchronize(VisitorSynchronization::SyncTag tag) override; 161 162 template <typename TSlot> 163 inline int WriteAddress(TSlot dest, Address value); 164 165 template <typename TSlot> 166 inline int WriteExternalPointer(TSlot dest, Address value, 167 ExternalPointerTag tag); 168 169 // Fills in a heap object's data from start to end (exclusive). Start and end 170 // are slot indices within the object. 171 void ReadData(Handle<HeapObject> object, int start_slot_index, 172 int end_slot_index); 173 174 // Fills in a contiguous range of full object slots (e.g. root pointers) from 175 // start to end (exclusive). 176 void ReadData(FullMaybeObjectSlot start, FullMaybeObjectSlot end); 177 178 // Helper for ReadData which reads the given bytecode and fills in some heap 179 // data into the given slot. May fill in zero or multiple slots, so it returns 180 // the number of slots filled. 181 template <typename SlotAccessor> 182 int ReadSingleBytecodeData(byte data, SlotAccessor slot_accessor); 183 184 // A helper function for ReadData for reading external references. 185 inline Address ReadExternalReferenceCase(); 186 187 // A helper function for reading external pointer tags. 188 ExternalPointerTag ReadExternalPointerTag(); 189 190 Handle<HeapObject> ReadObject(SnapshotSpace space_number); 191 Handle<HeapObject> ReadMetaMap(); 192 193 HeapObjectReferenceType GetAndResetNextReferenceType(); 194 195 template <typename SlotGetter> 196 int ReadRepeatedObject(SlotGetter slot_getter, int repeat_count); 197 198 // Special handling for serialized code like hooking up internalized strings. 199 void PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj, 200 SnapshotSpace space); 201 void PostProcessNewJSReceiver(Map map, Handle<JSReceiver> obj, 202 JSReceiver raw_obj, InstanceType instance_type, 203 SnapshotSpace space); 204 205 HeapObject Allocate(AllocationType allocation, int size, 206 AllocationAlignment alignment); 207 208 // Cached current isolate. 209 IsolateT* isolate_; 210 211 // Objects from the attached object descriptions in the serialized user code. 212 std::vector<Handle<HeapObject>> attached_objects_; 213 214 SnapshotByteSource source_; 215 uint32_t magic_number_; 216 217 HotObjectsList hot_objects_; 218 std::vector<Handle<Map>> new_maps_; 219 std::vector<Handle<AllocationSite>> new_allocation_sites_; 220 std::vector<Handle<Code>> new_code_objects_; 221 std::vector<Handle<AccessorInfo>> accessor_infos_; 222 std::vector<Handle<CallHandlerInfo>> call_handler_infos_; 223 std::vector<Handle<Script>> new_scripts_; 224 std::vector<Handle<JSArrayBuffer>> new_off_heap_array_buffers_; 225 std::vector<Handle<DescriptorArray>> new_descriptor_arrays_; 226 std::vector<std::shared_ptr<BackingStore>> backing_stores_; 227 228 // Vector of allocated objects that can be accessed by a backref, by index. 229 std::vector<Handle<HeapObject>> back_refs_; 230 231 // Unresolved forward references (registered with kRegisterPendingForwardRef) 232 // are collected in order as (object, field offset) pairs. The subsequent 233 // forward ref resolution (with kResolvePendingForwardRef) accesses this 234 // vector by index. 235 // 236 // The vector is cleared when there are no more unresolved forward refs. 237 struct UnresolvedForwardRef { UnresolvedForwardRefUnresolvedForwardRef238 UnresolvedForwardRef(Handle<HeapObject> object, int offset, 239 HeapObjectReferenceType ref_type) 240 : object(object), offset(offset), ref_type(ref_type) {} 241 242 Handle<HeapObject> object; 243 int offset; 244 HeapObjectReferenceType ref_type; 245 }; 246 std::vector<UnresolvedForwardRef> unresolved_forward_refs_; 247 int num_unresolved_forward_refs_ = 0; 248 249 const bool deserializing_user_code_; 250 251 bool next_reference_is_weak_ = false; 252 253 // TODO(6593): generalize rehashing, and remove this flag. 254 const bool should_rehash_; 255 std::vector<Handle<HeapObject>> to_rehash_; 256 257 #ifdef DEBUG 258 uint32_t num_api_references_; 259 260 // Record the previous object allocated for DCHECKs. 261 Handle<HeapObject> previous_allocation_obj_; 262 int previous_allocation_size_ = 0; 263 #endif // DEBUG 264 }; 265 266 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) 267 Deserializer<Isolate>; 268 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) 269 Deserializer<LocalIsolate>; 270 271 enum class DeserializingUserCodeOption { 272 kNotDeserializingUserCode, 273 kIsDeserializingUserCode 274 }; 275 276 // Used to insert a deserialized internalized string into the string table. 277 class StringTableInsertionKey final : public StringTableKey { 278 public: 279 explicit StringTableInsertionKey( 280 Isolate* isolate, Handle<String> string, 281 DeserializingUserCodeOption deserializing_user_code); 282 explicit StringTableInsertionKey( 283 LocalIsolate* isolate, Handle<String> string, 284 DeserializingUserCodeOption deserializing_user_code); 285 286 template <typename IsolateT> 287 bool IsMatch(IsolateT* isolate, String string); 288 PrepareForInsertion(Isolate * isolate)289 void PrepareForInsertion(Isolate* isolate) { 290 // When sharing the string table, all string table lookups during snapshot 291 // deserialization are hits. 292 DCHECK(isolate->OwnsStringTable() || 293 deserializing_user_code_ == 294 DeserializingUserCodeOption::kIsDeserializingUserCode); 295 } PrepareForInsertion(LocalIsolate * isolate)296 void PrepareForInsertion(LocalIsolate* isolate) {} GetHandleForInsertion()297 V8_WARN_UNUSED_RESULT Handle<String> GetHandleForInsertion() { 298 return string_; 299 } 300 301 private: 302 Handle<String> string_; 303 #ifdef DEBUG 304 DeserializingUserCodeOption deserializing_user_code_; 305 #endif 306 DISALLOW_GARBAGE_COLLECTION(no_gc) 307 }; 308 309 } // namespace internal 310 } // namespace v8 311 312 #endif // V8_SNAPSHOT_DESERIALIZER_H_ 313