| 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_
|
|
|