| // 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_SNAPSHOT_SERIALIZER_H_ |
| #define V8_SNAPSHOT_SERIALIZER_H_ |
| |
| #include <map> |
| |
| #include "src/isolate.h" |
| #include "src/log.h" |
| #include "src/objects.h" |
| #include "src/snapshot/default-serializer-allocator.h" |
| #include "src/snapshot/serializer-common.h" |
| #include "src/snapshot/snapshot-source-sink.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class CodeAddressMap : public CodeEventLogger { |
| public: |
| explicit CodeAddressMap(Isolate* isolate) : isolate_(isolate) { |
| isolate->logger()->addCodeEventListener(this); |
| } |
| |
| ~CodeAddressMap() override { |
| isolate_->logger()->removeCodeEventListener(this); |
| } |
| |
| void CodeMoveEvent(AbstractCode* from, Address to) override { |
| address_to_name_map_.Move(from->address(), to); |
| } |
| |
| void CodeDisableOptEvent(AbstractCode* code, |
| SharedFunctionInfo* shared) override {} |
| |
| const char* Lookup(Address address) { |
| return address_to_name_map_.Lookup(address); |
| } |
| |
| private: |
| class NameMap { |
| public: |
| NameMap() : impl_() {} |
| |
| ~NameMap() { |
| for (base::HashMap::Entry* p = impl_.Start(); p != nullptr; |
| p = impl_.Next(p)) { |
| DeleteArray(static_cast<const char*>(p->value)); |
| } |
| } |
| |
| void Insert(Address code_address, const char* name, int name_size) { |
| base::HashMap::Entry* entry = FindOrCreateEntry(code_address); |
| if (entry->value == nullptr) { |
| entry->value = CopyName(name, name_size); |
| } |
| } |
| |
| const char* Lookup(Address code_address) { |
| base::HashMap::Entry* entry = FindEntry(code_address); |
| return (entry != nullptr) ? static_cast<const char*>(entry->value) |
| : nullptr; |
| } |
| |
| void Remove(Address code_address) { |
| base::HashMap::Entry* entry = FindEntry(code_address); |
| if (entry != nullptr) { |
| DeleteArray(static_cast<char*>(entry->value)); |
| RemoveEntry(entry); |
| } |
| } |
| |
| void Move(Address from, Address to) { |
| if (from == to) return; |
| base::HashMap::Entry* from_entry = FindEntry(from); |
| DCHECK_NOT_NULL(from_entry); |
| void* value = from_entry->value; |
| RemoveEntry(from_entry); |
| base::HashMap::Entry* to_entry = FindOrCreateEntry(to); |
| DCHECK_NULL(to_entry->value); |
| to_entry->value = value; |
| } |
| |
| private: |
| static char* CopyName(const char* name, int name_size) { |
| char* result = NewArray<char>(name_size + 1); |
| for (int i = 0; i < name_size; ++i) { |
| char c = name[i]; |
| if (c == '\0') c = ' '; |
| result[i] = c; |
| } |
| result[name_size] = '\0'; |
| return result; |
| } |
| |
| base::HashMap::Entry* FindOrCreateEntry(Address code_address) { |
| return impl_.LookupOrInsert(code_address, |
| ComputePointerHash(code_address)); |
| } |
| |
| base::HashMap::Entry* FindEntry(Address code_address) { |
| return impl_.Lookup(code_address, ComputePointerHash(code_address)); |
| } |
| |
| void RemoveEntry(base::HashMap::Entry* entry) { |
| impl_.Remove(entry->key, entry->hash); |
| } |
| |
| base::HashMap impl_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NameMap); |
| }; |
| |
| void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*, |
| const char* name, int length) override { |
| address_to_name_map_.Insert(code->address(), name, length); |
| } |
| |
| NameMap address_to_name_map_; |
| Isolate* isolate_; |
| }; |
| |
| template <class AllocatorT = DefaultSerializerAllocator> |
| class Serializer : public SerializerDeserializer { |
| public: |
| explicit Serializer(Isolate* isolate); |
| ~Serializer() override; |
| |
| std::vector<SerializedData::Reservation> EncodeReservations() const { |
| return allocator_.EncodeReservations(); |
| } |
| |
| const std::vector<byte>* Payload() const { return sink_.data(); } |
| |
| bool ReferenceMapContains(HeapObject* o) { |
| return reference_map()->Lookup(o).is_valid(); |
| } |
| |
| Isolate* isolate() const { return isolate_; } |
| |
| protected: |
| class ObjectSerializer; |
| class RecursionScope { |
| public: |
| explicit RecursionScope(Serializer* serializer) : serializer_(serializer) { |
| serializer_->recursion_depth_++; |
| } |
| ~RecursionScope() { serializer_->recursion_depth_--; } |
| bool ExceedsMaximum() { |
| return serializer_->recursion_depth_ >= kMaxRecursionDepth; |
| } |
| |
| private: |
| static const int kMaxRecursionDepth = 32; |
| Serializer* serializer_; |
| }; |
| |
| void SerializeDeferredObjects(); |
| virtual void SerializeObject(HeapObject* o, HowToCode how_to_code, |
| WhereToPoint where_to_point, int skip) = 0; |
| |
| virtual bool MustBeDeferred(HeapObject* object); |
| |
| void VisitRootPointers(Root root, Object** start, Object** end) override; |
| |
| void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where, |
| int skip); |
| void PutSmi(Smi* smi); |
| void PutBackReference(HeapObject* object, SerializerReference reference); |
| void PutAttachedReference(SerializerReference reference, |
| HowToCode how_to_code, WhereToPoint where_to_point); |
| // Emit alignment prefix if necessary, return required padding space in bytes. |
| int PutAlignmentPrefix(HeapObject* object); |
| void PutNextChunk(int space); |
| |
| // Returns true if the object was successfully serialized as hot object. |
| bool SerializeHotObject(HeapObject* obj, HowToCode how_to_code, |
| WhereToPoint where_to_point, int skip); |
| |
| // Returns true if the object was successfully serialized as back reference. |
| bool SerializeBackReference(HeapObject* obj, HowToCode how_to_code, |
| WhereToPoint where_to_point, int skip); |
| |
| // Determines whether the interpreter trampoline is replaced by CompileLazy. |
| enum BuiltinReferenceSerializationMode { |
| kDefault, |
| kCanonicalizeCompileLazy, |
| }; |
| |
| // Returns true if the object was successfully serialized as a builtin |
| // reference. |
| bool SerializeBuiltinReference( |
| HeapObject* obj, HowToCode how_to_code, WhereToPoint where_to_point, |
| int skip, BuiltinReferenceSerializationMode mode = kDefault); |
| |
| // Returns true if the given heap object is a bytecode handler code object. |
| bool ObjectIsBytecodeHandler(HeapObject* obj) const; |
| |
| inline void FlushSkip(int skip) { |
| if (skip != 0) { |
| sink_.Put(kSkip, "SkipFromSerializeObject"); |
| sink_.PutInt(skip, "SkipDistanceFromSerializeObject"); |
| } |
| } |
| |
| ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) { |
| return external_reference_encoder_.Encode(addr); |
| } |
| |
| // GetInt reads 4 bytes at once, requiring padding at the end. |
| void Pad(); |
| |
| // We may not need the code address map for logging for every instance |
| // of the serializer. Initialize it on demand. |
| void InitializeCodeAddressMap(); |
| |
| Code* CopyCode(Code* code); |
| |
| void QueueDeferredObject(HeapObject* obj) { |
| DCHECK(reference_map_.Lookup(obj).is_back_reference()); |
| deferred_objects_.push_back(obj); |
| } |
| |
| void OutputStatistics(const char* name); |
| |
| #ifdef OBJECT_PRINT |
| void CountInstanceType(Map* map, int size); |
| #endif // OBJECT_PRINT |
| |
| #ifdef DEBUG |
| void PushStack(HeapObject* o) { stack_.push_back(o); } |
| void PopStack() { stack_.pop_back(); } |
| void PrintStack(); |
| #endif // DEBUG |
| |
| SerializerReferenceMap* reference_map() { return &reference_map_; } |
| RootIndexMap* root_index_map() { return &root_index_map_; } |
| AllocatorT* allocator() { return &allocator_; } |
| |
| SnapshotByteSink sink_; // Used directly by subclasses. |
| |
| private: |
| Isolate* isolate_; |
| SerializerReferenceMap reference_map_; |
| ExternalReferenceEncoder external_reference_encoder_; |
| RootIndexMap root_index_map_; |
| CodeAddressMap* code_address_map_ = nullptr; |
| std::vector<byte> code_buffer_; |
| std::vector<HeapObject*> deferred_objects_; // To handle stack overflow. |
| int recursion_depth_ = 0; |
| AllocatorT allocator_; |
| |
| #ifdef OBJECT_PRINT |
| static const int kInstanceTypes = LAST_TYPE + 1; |
| int* instance_type_count_; |
| size_t* instance_type_size_; |
| #endif // OBJECT_PRINT |
| |
| #ifdef DEBUG |
| std::vector<HeapObject*> stack_; |
| #endif // DEBUG |
| |
| friend class DefaultSerializerAllocator; |
| |
| DISALLOW_COPY_AND_ASSIGN(Serializer); |
| }; |
| |
| template <class AllocatorT> |
| class Serializer<AllocatorT>::ObjectSerializer : public ObjectVisitor { |
| public: |
| ObjectSerializer(Serializer* serializer, HeapObject* obj, |
| SnapshotByteSink* sink, HowToCode how_to_code, |
| WhereToPoint where_to_point) |
| : serializer_(serializer), |
| object_(obj), |
| sink_(sink), |
| reference_representation_(how_to_code + where_to_point), |
| bytes_processed_so_far_(0) { |
| #ifdef DEBUG |
| serializer_->PushStack(obj); |
| #endif // DEBUG |
| } |
| ~ObjectSerializer() override { |
| #ifdef DEBUG |
| serializer_->PopStack(); |
| #endif // DEBUG |
| } |
| void Serialize(); |
| void SerializeObject(); |
| void SerializeDeferred(); |
| void VisitPointers(HeapObject* host, Object** start, Object** end) override; |
| void VisitEmbeddedPointer(Code* host, RelocInfo* target) override; |
| void VisitExternalReference(Foreign* host, Address* p) override; |
| void VisitExternalReference(Code* host, RelocInfo* rinfo) override; |
| void VisitInternalReference(Code* host, RelocInfo* rinfo) override; |
| void VisitCodeTarget(Code* host, RelocInfo* target) override; |
| void VisitRuntimeEntry(Code* host, RelocInfo* reloc) override; |
| |
| private: |
| void SerializePrologue(AllocationSpace space, int size, Map* map); |
| |
| // This function outputs or skips the raw data between the last pointer and |
| // up to the current position. |
| void SerializeContent(Map* map, int size); |
| void OutputRawData(Address up_to); |
| void OutputCode(int size); |
| int SkipTo(Address to); |
| int32_t SerializeBackingStore(void* backing_store, int32_t byte_length); |
| void SerializeJSTypedArray(); |
| void SerializeJSArrayBuffer(); |
| void SerializeExternalString(); |
| void SerializeExternalStringAsSequentialString(); |
| |
| Serializer* serializer_; |
| HeapObject* object_; |
| SnapshotByteSink* sink_; |
| std::map<void*, Smi*> backing_stores; |
| int reference_representation_; |
| int bytes_processed_so_far_; |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_SNAPSHOT_SERIALIZER_H_ |