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_SERIALIZER_H_ 6 #define V8_SNAPSHOT_SERIALIZER_H_ 7 8 #include <map> 9 10 #include "src/codegen/external-reference-encoder.h" 11 #include "src/common/assert-scope.h" 12 #include "src/execution/isolate.h" 13 #include "src/handles/global-handles.h" 14 #include "src/logging/log.h" 15 #include "src/objects/objects.h" 16 #include "src/snapshot/embedded/embedded-data.h" 17 #include "src/snapshot/serializer-deserializer.h" 18 #include "src/snapshot/snapshot-source-sink.h" 19 #include "src/snapshot/snapshot.h" 20 #include "src/utils/identity-map.h" 21 22 namespace v8 { 23 namespace internal { 24 25 class CodeAddressMap : public CodeEventLogger { 26 public: CodeAddressMap(Isolate * isolate)27 explicit CodeAddressMap(Isolate* isolate) : CodeEventLogger(isolate) { 28 isolate->logger()->AddCodeEventListener(this); 29 } 30 ~CodeAddressMap()31 ~CodeAddressMap() override { 32 isolate_->logger()->RemoveCodeEventListener(this); 33 } 34 CodeMoveEvent(AbstractCode from,AbstractCode to)35 void CodeMoveEvent(AbstractCode from, AbstractCode to) override { 36 address_to_name_map_.Move(from.address(), to.address()); 37 } 38 CodeDisableOptEvent(Handle<AbstractCode> code,Handle<SharedFunctionInfo> shared)39 void CodeDisableOptEvent(Handle<AbstractCode> code, 40 Handle<SharedFunctionInfo> shared) override {} 41 Lookup(Address address)42 const char* Lookup(Address address) { 43 return address_to_name_map_.Lookup(address); 44 } 45 46 private: 47 class NameMap { 48 public: NameMap()49 NameMap() : impl_() {} 50 NameMap(const NameMap&) = delete; 51 NameMap& operator=(const NameMap&) = delete; 52 ~NameMap()53 ~NameMap() { 54 for (base::HashMap::Entry* p = impl_.Start(); p != nullptr; 55 p = impl_.Next(p)) { 56 DeleteArray(static_cast<const char*>(p->value)); 57 } 58 } 59 Insert(Address code_address,const char * name,int name_size)60 void Insert(Address code_address, const char* name, int name_size) { 61 base::HashMap::Entry* entry = FindOrCreateEntry(code_address); 62 if (entry->value == nullptr) { 63 entry->value = CopyName(name, name_size); 64 } 65 } 66 Lookup(Address code_address)67 const char* Lookup(Address code_address) { 68 base::HashMap::Entry* entry = FindEntry(code_address); 69 return (entry != nullptr) ? static_cast<const char*>(entry->value) 70 : nullptr; 71 } 72 Remove(Address code_address)73 void Remove(Address code_address) { 74 base::HashMap::Entry* entry = FindEntry(code_address); 75 if (entry != nullptr) { 76 DeleteArray(static_cast<char*>(entry->value)); 77 RemoveEntry(entry); 78 } 79 } 80 Move(Address from,Address to)81 void Move(Address from, Address to) { 82 if (from == to) return; 83 base::HashMap::Entry* from_entry = FindEntry(from); 84 DCHECK_NOT_NULL(from_entry); 85 void* value = from_entry->value; 86 RemoveEntry(from_entry); 87 base::HashMap::Entry* to_entry = FindOrCreateEntry(to); 88 DCHECK_NULL(to_entry->value); 89 to_entry->value = value; 90 } 91 92 private: CopyName(const char * name,int name_size)93 static char* CopyName(const char* name, int name_size) { 94 char* result = NewArray<char>(name_size + 1); 95 for (int i = 0; i < name_size; ++i) { 96 char c = name[i]; 97 if (c == '\0') c = ' '; 98 result[i] = c; 99 } 100 result[name_size] = '\0'; 101 return result; 102 } 103 FindOrCreateEntry(Address code_address)104 base::HashMap::Entry* FindOrCreateEntry(Address code_address) { 105 return impl_.LookupOrInsert(reinterpret_cast<void*>(code_address), 106 ComputeAddressHash(code_address)); 107 } 108 FindEntry(Address code_address)109 base::HashMap::Entry* FindEntry(Address code_address) { 110 return impl_.Lookup(reinterpret_cast<void*>(code_address), 111 ComputeAddressHash(code_address)); 112 } 113 RemoveEntry(base::HashMap::Entry * entry)114 void RemoveEntry(base::HashMap::Entry* entry) { 115 impl_.Remove(entry->key, entry->hash); 116 } 117 118 base::HashMap impl_; 119 }; 120 LogRecordedBuffer(Handle<AbstractCode> code,MaybeHandle<SharedFunctionInfo>,const char * name,int length)121 void LogRecordedBuffer(Handle<AbstractCode> code, 122 MaybeHandle<SharedFunctionInfo>, const char* name, 123 int length) override { 124 address_to_name_map_.Insert(code->address(), name, length); 125 } 126 LogRecordedBuffer(const wasm::WasmCode * code,const char * name,int length)127 void LogRecordedBuffer(const wasm::WasmCode* code, const char* name, 128 int length) override { 129 UNREACHABLE(); 130 } 131 132 NameMap address_to_name_map_; 133 }; 134 135 class ObjectCacheIndexMap { 136 public: ObjectCacheIndexMap(Heap * heap)137 explicit ObjectCacheIndexMap(Heap* heap) : map_(heap), next_index_(0) {} 138 ObjectCacheIndexMap(const ObjectCacheIndexMap&) = delete; 139 ObjectCacheIndexMap& operator=(const ObjectCacheIndexMap&) = delete; 140 141 // If |obj| is in the map, immediately return true. Otherwise add it to the 142 // map and return false. In either case set |*index_out| to the index 143 // associated with the map. LookupOrInsert(Handle<HeapObject> obj,int * index_out)144 bool LookupOrInsert(Handle<HeapObject> obj, int* index_out) { 145 auto find_result = map_.FindOrInsert(obj); 146 if (!find_result.already_exists) { 147 *find_result.entry = next_index_++; 148 } 149 *index_out = *find_result.entry; 150 return find_result.already_exists; 151 } 152 153 private: 154 DisallowHeapAllocation no_allocation_; 155 156 IdentityMap<int, base::DefaultAllocationPolicy> map_; 157 int next_index_; 158 }; 159 160 class Serializer : public SerializerDeserializer { 161 public: 162 Serializer(Isolate* isolate, Snapshot::SerializerFlags flags); ~Serializer()163 ~Serializer() override { DCHECK_EQ(unresolved_forward_refs_, 0); } 164 Serializer(const Serializer&) = delete; 165 Serializer& operator=(const Serializer&) = delete; 166 Payload()167 const std::vector<byte>* Payload() const { return sink_.data(); } 168 ReferenceMapContains(Handle<HeapObject> o)169 bool ReferenceMapContains(Handle<HeapObject> o) { 170 return reference_map()->LookupReference(o) != nullptr; 171 } 172 isolate()173 Isolate* isolate() const { return isolate_; } 174 175 int TotalAllocationSize() const; 176 177 protected: 178 using PendingObjectReferences = std::vector<int>*; 179 180 class ObjectSerializer; 181 class RecursionScope { 182 public: RecursionScope(Serializer * serializer)183 explicit RecursionScope(Serializer* serializer) : serializer_(serializer) { 184 serializer_->recursion_depth_++; 185 } ~RecursionScope()186 ~RecursionScope() { serializer_->recursion_depth_--; } ExceedsMaximum()187 bool ExceedsMaximum() { 188 return serializer_->recursion_depth_ >= kMaxRecursionDepth; 189 } 190 191 private: 192 static const int kMaxRecursionDepth = 32; 193 Serializer* serializer_; 194 }; 195 196 void SerializeDeferredObjects(); 197 void SerializeObject(Handle<HeapObject> o); 198 virtual void SerializeObjectImpl(Handle<HeapObject> o) = 0; 199 200 virtual bool MustBeDeferred(HeapObject object); 201 202 void VisitRootPointers(Root root, const char* description, 203 FullObjectSlot start, FullObjectSlot end) override; 204 void SerializeRootObject(FullObjectSlot slot); 205 206 void PutRoot(RootIndex root_index); 207 void PutSmiRoot(FullObjectSlot slot); 208 void PutBackReference(Handle<HeapObject> object, 209 SerializerReference reference); 210 void PutAttachedReference(SerializerReference reference); 211 void PutNextChunk(SnapshotSpace space); 212 void PutRepeat(int repeat_count); 213 214 // Emit a marker noting that this slot is a forward reference to the an 215 // object which has not yet been serialized. 216 void PutPendingForwardReference(PendingObjectReferences& ref); 217 // Resolve the given previously registered forward reference to the current 218 // object. 219 void ResolvePendingForwardReference(int obj); 220 221 // Returns true if the object was successfully serialized as a root. 222 bool SerializeRoot(Handle<HeapObject> obj); 223 224 // Returns true if the object was successfully serialized as hot object. 225 bool SerializeHotObject(Handle<HeapObject> obj); 226 227 // Returns true if the object was successfully serialized as back reference. 228 bool SerializeBackReference(Handle<HeapObject> obj); 229 230 // Returns true if the object was successfully serialized as pending object. 231 bool SerializePendingObject(Handle<HeapObject> obj); 232 233 // Returns true if the given heap object is a bytecode handler code object. 234 bool ObjectIsBytecodeHandler(Handle<HeapObject> obj) const; 235 EncodeExternalReference(Address addr)236 ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) { 237 return external_reference_encoder_.Encode(addr); 238 } TryEncodeExternalReference(Address addr)239 Maybe<ExternalReferenceEncoder::Value> TryEncodeExternalReference( 240 Address addr) { 241 return external_reference_encoder_.TryEncode(addr); 242 } 243 244 // GetInt reads 4 bytes at once, requiring padding at the end. 245 // Use padding_offset to specify the space you want to use after padding. 246 void Pad(int padding_offset = 0); 247 248 // We may not need the code address map for logging for every instance 249 // of the serializer. Initialize it on demand. 250 void InitializeCodeAddressMap(); 251 252 Code CopyCode(Code code); 253 QueueDeferredObject(Handle<HeapObject> obj)254 void QueueDeferredObject(Handle<HeapObject> obj) { 255 DCHECK_NULL(reference_map_.LookupReference(obj)); 256 deferred_objects_.Push(*obj); 257 } 258 259 // Register that the the given object shouldn't be immediately serialized, but 260 // will be serialized later and any references to it should be pending forward 261 // references. 262 void RegisterObjectIsPending(Handle<HeapObject> obj); 263 264 // Resolve the given pending object reference with the current object. 265 void ResolvePendingObject(Handle<HeapObject> obj); 266 267 void OutputStatistics(const char* name); 268 269 void CountAllocation(Map map, int size, SnapshotSpace space); 270 271 #ifdef DEBUG PushStack(Handle<HeapObject> o)272 void PushStack(Handle<HeapObject> o) { stack_.Push(*o); } PopStack()273 void PopStack() { stack_.Pop(); } 274 void PrintStack(); 275 void PrintStack(std::ostream&); 276 #endif // DEBUG 277 reference_map()278 SerializerReferenceMap* reference_map() { return &reference_map_; } root_index_map()279 const RootIndexMap* root_index_map() const { return &root_index_map_; } 280 281 SnapshotByteSink sink_; // Used directly by subclasses. 282 allow_unknown_external_references_for_testing()283 bool allow_unknown_external_references_for_testing() const { 284 return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0; 285 } allow_active_isolate_for_testing()286 bool allow_active_isolate_for_testing() const { 287 return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0; 288 } 289 290 private: 291 // A circular queue of hot objects. This is added to in the same order as in 292 // Deserializer::HotObjectsList, but this stores the objects as an array of 293 // raw addresses that are considered strong roots. This allows objects to be 294 // added to the list without having to extend their handle's lifetime. 295 // 296 // We should never allow this class to return Handles to objects in the queue, 297 // as the object in the queue may change if kSize other objects are added to 298 // the queue during that Handle's lifetime. 299 class HotObjectsList { 300 public: 301 explicit HotObjectsList(Heap* heap); 302 ~HotObjectsList(); 303 HotObjectsList(const HotObjectsList&) = delete; 304 HotObjectsList& operator=(const HotObjectsList&) = delete; 305 Add(HeapObject object)306 void Add(HeapObject object) { 307 circular_queue_[index_] = object.ptr(); 308 index_ = (index_ + 1) & kSizeMask; 309 } 310 311 static const int kNotFound = -1; 312 Find(HeapObject object)313 int Find(HeapObject object) { 314 DCHECK(!AllowGarbageCollection::IsAllowed()); 315 for (int i = 0; i < kSize; i++) { 316 if (circular_queue_[i] == object.ptr()) { 317 return i; 318 } 319 } 320 return kNotFound; 321 } 322 323 private: 324 static const int kSize = kHotObjectCount; 325 static const int kSizeMask = kSize - 1; 326 STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize)); 327 Heap* heap_; 328 StrongRootsEntry* strong_roots_entry_; 329 Address circular_queue_[kSize] = {kNullAddress}; 330 int index_ = 0; 331 }; 332 333 // Disallow GC during serialization. 334 // TODO(leszeks, v8:10815): Remove this constraint. 335 DISALLOW_HEAP_ALLOCATION(no_gc) 336 337 Isolate* isolate_; 338 HotObjectsList hot_objects_; 339 SerializerReferenceMap reference_map_; 340 ExternalReferenceEncoder external_reference_encoder_; 341 RootIndexMap root_index_map_; 342 std::unique_ptr<CodeAddressMap> code_address_map_; 343 std::vector<byte> code_buffer_; 344 GlobalHandleVector<HeapObject> 345 deferred_objects_; // To handle stack overflow. 346 int num_back_refs_ = 0; 347 348 // Objects which have started being serialized, but haven't yet been allocated 349 // with the allocator, are considered "pending". References to them don't have 350 // an allocation to backref to, so instead they are registered as pending 351 // forward references, which are resolved once the object is allocated. 352 // 353 // Forward references are registered in a deterministic order, and can 354 // therefore be identified by an incrementing integer index, which is 355 // effectively an index into a vector of the currently registered forward 356 // refs. The references in this vector might not be resolved in order, so we 357 // can only clear it (and reset the indices) when there are no unresolved 358 // forward refs remaining. 359 int next_forward_ref_id_ = 0; 360 int unresolved_forward_refs_ = 0; 361 IdentityMap<PendingObjectReferences, base::DefaultAllocationPolicy> 362 forward_refs_per_pending_object_; 363 364 // Used to keep track of the off-heap backing stores used by TypedArrays/ 365 // ArrayBuffers. Note that the index begins at 1 and not 0, because when a 366 // TypedArray has an on-heap backing store, the backing_store pointer in the 367 // corresponding ArrayBuffer will be null, which makes it indistinguishable 368 // from index 0. 369 uint32_t seen_backing_stores_index_ = 1; 370 371 int recursion_depth_ = 0; 372 const Snapshot::SerializerFlags flags_; 373 374 size_t allocation_size_[kNumberOfSnapshotSpaces] = {0}; 375 #ifdef OBJECT_PRINT 376 static constexpr int kInstanceTypes = LAST_TYPE + 1; 377 std::unique_ptr<int[]> instance_type_count_[kNumberOfSnapshotSpaces]; 378 std::unique_ptr<size_t[]> instance_type_size_[kNumberOfSnapshotSpaces]; 379 #endif // OBJECT_PRINT 380 381 #ifdef DEBUG 382 GlobalHandleVector<HeapObject> back_refs_; 383 GlobalHandleVector<HeapObject> stack_; 384 #endif // DEBUG 385 }; 386 387 class RelocInfoIterator; 388 389 class Serializer::ObjectSerializer : public ObjectVisitor { 390 public: ObjectSerializer(Serializer * serializer,Handle<HeapObject> obj,SnapshotByteSink * sink)391 ObjectSerializer(Serializer* serializer, Handle<HeapObject> obj, 392 SnapshotByteSink* sink) 393 : isolate_(serializer->isolate()), 394 serializer_(serializer), 395 object_(obj), 396 sink_(sink), 397 bytes_processed_so_far_(0) { 398 #ifdef DEBUG 399 serializer_->PushStack(obj); 400 #endif // DEBUG 401 } 402 // NOLINTNEXTLINE (modernize-use-equals-default) ~ObjectSerializer()403 ~ObjectSerializer() override { 404 #ifdef DEBUG 405 serializer_->PopStack(); 406 #endif // DEBUG 407 } 408 void Serialize(); 409 void SerializeObject(); 410 void SerializeDeferred(); 411 void VisitPointers(HeapObject host, ObjectSlot start, 412 ObjectSlot end) override; 413 void VisitPointers(HeapObject host, MaybeObjectSlot start, 414 MaybeObjectSlot end) override; 415 void VisitEmbeddedPointer(Code host, RelocInfo* target) override; 416 void VisitExternalReference(Foreign host, Address* p) override; 417 void VisitExternalReference(Code host, RelocInfo* rinfo) override; 418 void VisitInternalReference(Code host, RelocInfo* rinfo) override; 419 void VisitCodeTarget(Code host, RelocInfo* target) override; 420 void VisitRuntimeEntry(Code host, RelocInfo* reloc) override; 421 void VisitOffHeapTarget(Code host, RelocInfo* target) override; 422 isolate()423 Isolate* isolate() { return isolate_; } 424 425 private: 426 class RelocInfoObjectPreSerializer; 427 428 void SerializePrologue(SnapshotSpace space, int size, Map map); 429 430 // This function outputs or skips the raw data between the last pointer and 431 // up to the current position. 432 void SerializeContent(Map map, int size); 433 void OutputExternalReference(Address target, int target_size, 434 bool sandboxify); 435 void OutputRawData(Address up_to); 436 void SerializeCode(Map map, int size); 437 uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length); 438 void SerializeJSTypedArray(); 439 void SerializeJSArrayBuffer(); 440 void SerializeExternalString(); 441 void SerializeExternalStringAsSequentialString(); 442 443 Isolate* isolate_; 444 Serializer* serializer_; 445 Handle<HeapObject> object_; 446 SnapshotByteSink* sink_; 447 int bytes_processed_so_far_; 448 }; 449 450 } // namespace internal 451 } // namespace v8 452 453 #endif // V8_SNAPSHOT_SERIALIZER_H_ 454