Index: src/snapshot/serializer.h |
diff --git a/src/snapshot/serializer.h b/src/snapshot/serializer.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca00e689f544920bec590dc6da39852e840ea563 |
--- /dev/null |
+++ b/src/snapshot/serializer.h |
@@ -0,0 +1,321 @@ |
+// 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 "src/isolate.h" |
+#include "src/log.h" |
+#include "src/objects.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_(HashMap::PointersMatch) {} |
+ |
+ ~NameMap() { |
+ for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) { |
+ DeleteArray(static_cast<const char*>(p->value)); |
+ } |
+ } |
+ |
+ void Insert(Address code_address, const char* name, int name_size) { |
+ HashMap::Entry* entry = FindOrCreateEntry(code_address); |
+ if (entry->value == NULL) { |
+ entry->value = CopyName(name, name_size); |
+ } |
+ } |
+ |
+ const char* Lookup(Address code_address) { |
+ HashMap::Entry* entry = FindEntry(code_address); |
+ return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL; |
+ } |
+ |
+ void Remove(Address code_address) { |
+ HashMap::Entry* entry = FindEntry(code_address); |
+ if (entry != NULL) { |
+ DeleteArray(static_cast<char*>(entry->value)); |
+ RemoveEntry(entry); |
+ } |
+ } |
+ |
+ void Move(Address from, Address to) { |
+ if (from == to) return; |
+ HashMap::Entry* from_entry = FindEntry(from); |
+ DCHECK(from_entry != NULL); |
+ void* value = from_entry->value; |
+ RemoveEntry(from_entry); |
+ HashMap::Entry* to_entry = FindOrCreateEntry(to); |
+ DCHECK(to_entry->value == NULL); |
+ 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; |
+ } |
+ |
+ HashMap::Entry* FindOrCreateEntry(Address code_address) { |
+ return impl_.LookupOrInsert(code_address, |
+ ComputePointerHash(code_address)); |
+ } |
+ |
+ HashMap::Entry* FindEntry(Address code_address) { |
+ return impl_.Lookup(code_address, ComputePointerHash(code_address)); |
+ } |
+ |
+ void RemoveEntry(HashMap::Entry* entry) { |
+ impl_.Remove(entry->key, entry->hash); |
+ } |
+ |
+ 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_; |
+}; |
+ |
+// There can be only one serializer per V8 process. |
+class Serializer : public SerializerDeserializer { |
+ public: |
+ Serializer(Isolate* isolate, SnapshotByteSink* sink); |
+ ~Serializer() override; |
+ |
+ void EncodeReservations(List<SerializedData::Reservation>* out) const; |
+ |
+ void SerializeDeferredObjects(); |
+ |
+ Isolate* isolate() const { return isolate_; } |
+ |
+ BackReferenceMap* back_reference_map() { return &back_reference_map_; } |
+ RootIndexMap* root_index_map() { return &root_index_map_; } |
+ |
+#ifdef OBJECT_PRINT |
+ void CountInstanceType(Map* map, int size); |
+#endif // OBJECT_PRINT |
+ |
+ 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_; |
+ }; |
+ |
+ virtual void SerializeObject(HeapObject* o, HowToCode how_to_code, |
+ WhereToPoint where_to_point, int skip) = 0; |
+ |
+ void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where, |
+ int skip); |
+ |
+ void PutBackReference(HeapObject* object, BackReference reference); |
+ |
+ // Emit alignment prefix if necessary, return required padding space in bytes. |
+ int PutAlignmentPrefix(HeapObject* object); |
+ |
+ // Returns true if the object was successfully serialized. |
+ bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code, |
+ WhereToPoint where_to_point, int skip); |
+ |
+ inline void FlushSkip(int skip) { |
+ if (skip != 0) { |
+ sink_->Put(kSkip, "SkipFromSerializeObject"); |
+ sink_->PutInt(skip, "SkipDistanceFromSerializeObject"); |
+ } |
+ } |
+ |
+ bool BackReferenceIsAlreadyAllocated(BackReference back_reference); |
+ |
+ // This will return the space for an object. |
+ BackReference AllocateLargeObject(int size); |
+ BackReference Allocate(AllocationSpace space, int size); |
+ int EncodeExternalReference(Address addr) { |
+ return external_reference_encoder_.Encode(addr); |
+ } |
+ |
+ // GetInt reads 4 bytes at once, requiring padding at the end. |
+ void Pad(); |
+ |
+ // Some roots should not be serialized, because their actual value depends on |
+ // absolute addresses and they are reset after deserialization, anyway. |
+ bool ShouldBeSkipped(Object** current); |
+ |
+ // 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); |
+ |
+ inline uint32_t max_chunk_size(int space) const { |
+ DCHECK_LE(0, space); |
+ DCHECK_LT(space, kNumberOfSpaces); |
+ return max_chunk_size_[space]; |
+ } |
+ |
+ SnapshotByteSink* sink() const { return sink_; } |
+ |
+ void QueueDeferredObject(HeapObject* obj) { |
+ DCHECK(back_reference_map_.Lookup(obj).is_valid()); |
+ deferred_objects_.Add(obj); |
+ } |
+ |
+ void OutputStatistics(const char* name); |
+ |
+ Isolate* isolate_; |
+ |
+ SnapshotByteSink* sink_; |
+ ExternalReferenceEncoder external_reference_encoder_; |
+ |
+ BackReferenceMap back_reference_map_; |
+ RootIndexMap root_index_map_; |
+ |
+ int recursion_depth_; |
+ |
+ friend class Deserializer; |
+ friend class ObjectSerializer; |
+ friend class RecursionScope; |
+ friend class SnapshotData; |
+ |
+ private: |
+ void VisitPointers(Object** start, Object** end) override; |
+ |
+ CodeAddressMap* code_address_map_; |
+ // Objects from the same space are put into chunks for bulk-allocation |
+ // when deserializing. We have to make sure that each chunk fits into a |
+ // page. So we track the chunk size in pending_chunk_ of a space, but |
+ // when it exceeds a page, we complete the current chunk and start a new one. |
+ uint32_t pending_chunk_[kNumberOfPreallocatedSpaces]; |
+ List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces]; |
+ uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces]; |
+ |
+ // We map serialized large objects to indexes for back-referencing. |
+ uint32_t large_objects_total_size_; |
+ uint32_t seen_large_objects_index_; |
+ |
+ List<byte> code_buffer_; |
+ |
+ // To handle stack overflow. |
+ List<HeapObject*> deferred_objects_; |
+ |
+#ifdef OBJECT_PRINT |
+ static const int kInstanceTypes = 256; |
+ int* instance_type_count_; |
+ size_t* instance_type_size_; |
+#endif // OBJECT_PRINT |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Serializer); |
+}; |
+ |
+class Serializer::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), |
+ code_has_been_output_(false) {} |
+ ~ObjectSerializer() override {} |
+ void Serialize(); |
+ void SerializeDeferred(); |
+ void VisitPointers(Object** start, Object** end) override; |
+ void VisitEmbeddedPointer(RelocInfo* target) override; |
+ void VisitExternalReference(Address* p) override; |
+ void VisitExternalReference(RelocInfo* rinfo) override; |
+ void VisitInternalReference(RelocInfo* rinfo) override; |
+ void VisitCodeTarget(RelocInfo* target) override; |
+ void VisitCodeEntry(Address entry_address) override; |
+ void VisitCell(RelocInfo* rinfo) override; |
+ void VisitRuntimeEntry(RelocInfo* reloc) override; |
+ // Used for seralizing the external strings that hold the natives source. |
+ void VisitExternalOneByteString( |
+ v8::String::ExternalOneByteStringResource** resource) override; |
+ // We can't serialize a heap with external two byte strings. |
+ void VisitExternalTwoByteString( |
+ v8::String::ExternalStringResource** resource) override { |
+ UNREACHABLE(); |
+ } |
+ |
+ private: |
+ void SerializePrologue(AllocationSpace space, int size, Map* map); |
+ |
+ bool SerializeExternalNativeSourceString( |
+ int builtin_count, |
+ v8::String::ExternalOneByteStringResource** resource_pointer, |
+ FixedArray* source_cache, int resource_index); |
+ |
+ enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn }; |
+ // This function outputs or skips the raw data between the last pointer and |
+ // up to the current position. It optionally can just return the number of |
+ // bytes to skip instead of performing a skip instruction, in case the skip |
+ // can be merged into the next instruction. |
+ int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn); |
+ // External strings are serialized in a way to resemble sequential strings. |
+ void SerializeExternalString(); |
+ |
+ Address PrepareCode(); |
+ |
+ Serializer* serializer_; |
+ HeapObject* object_; |
+ SnapshotByteSink* sink_; |
+ int reference_representation_; |
+ int bytes_processed_so_far_; |
+ bool code_has_been_output_; |
+}; |
+ |
+} // namespace internal |
+} // namespace v8 |
+ |
+#endif // V8_SNAPSHOT_SERIALIZER_H_ |