diff options
Diffstat (limited to 'src/3rdparty/v8/src/serialize.h')
-rw-r--r-- | src/3rdparty/v8/src/serialize.h | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/src/3rdparty/v8/src/serialize.h b/src/3rdparty/v8/src/serialize.h new file mode 100644 index 0000000..07c0a25 --- /dev/null +++ b/src/3rdparty/v8/src/serialize.h @@ -0,0 +1,589 @@ +// Copyright 2006-2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef V8_SERIALIZE_H_ +#define V8_SERIALIZE_H_ + +#include "hashmap.h" + +namespace v8 { +namespace internal { + +// A TypeCode is used to distinguish different kinds of external reference. +// It is a single bit to make testing for types easy. +enum TypeCode { + UNCLASSIFIED, // One-of-a-kind references. + BUILTIN, + RUNTIME_FUNCTION, + IC_UTILITY, + DEBUG_ADDRESS, + STATS_COUNTER, + TOP_ADDRESS, + C_BUILTIN, + EXTENSION, + ACCESSOR, + RUNTIME_ENTRY, + STUB_CACHE_TABLE +}; + +const int kTypeCodeCount = STUB_CACHE_TABLE + 1; +const int kFirstTypeCode = UNCLASSIFIED; + +const int kReferenceIdBits = 16; +const int kReferenceIdMask = (1 << kReferenceIdBits) - 1; +const int kReferenceTypeShift = kReferenceIdBits; +const int kDebugRegisterBits = 4; +const int kDebugIdShift = kDebugRegisterBits; + + +class ExternalReferenceEncoder { + public: + ExternalReferenceEncoder(); + + uint32_t Encode(Address key) const; + + const char* NameOfAddress(Address key) const; + + private: + HashMap encodings_; + static uint32_t Hash(Address key) { + return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key) >> 2); + } + + int IndexOf(Address key) const; + + static bool Match(void* key1, void* key2) { return key1 == key2; } + + void Put(Address key, int index); + + Isolate* isolate_; +}; + + +class ExternalReferenceDecoder { + public: + ExternalReferenceDecoder(); + ~ExternalReferenceDecoder(); + + Address Decode(uint32_t key) const { + if (key == 0) return NULL; + return *Lookup(key); + } + + private: + Address** encodings_; + + Address* Lookup(uint32_t key) const { + int type = key >> kReferenceTypeShift; + ASSERT(kFirstTypeCode <= type && type < kTypeCodeCount); + int id = key & kReferenceIdMask; + return &encodings_[type][id]; + } + + void Put(uint32_t key, Address value) { + *Lookup(key) = value; + } + + Isolate* isolate_; +}; + + +class SnapshotByteSource { + public: + SnapshotByteSource(const byte* array, int length) + : data_(array), length_(length), position_(0) { } + + bool HasMore() { return position_ < length_; } + + int Get() { + ASSERT(position_ < length_); + return data_[position_++]; + } + + inline void CopyRaw(byte* to, int number_of_bytes); + + inline int GetInt(); + + bool AtEOF() { + return position_ == length_; + } + + int position() { return position_; } + + private: + const byte* data_; + int length_; + int position_; +}; + + +// It is very common to have a reference to objects at certain offsets in the +// heap. These offsets have been determined experimentally. We code +// references to such objects in a single byte that encodes the way the pointer +// is written (only plain pointers allowed), the space number and the offset. +// This only works for objects in the first page of a space. Don't use this for +// things in newspace since it bypasses the write barrier. + +RLYSTC const int k64 = (sizeof(uintptr_t) - 4) / 4; + +#define COMMON_REFERENCE_PATTERNS(f) \ + f(kNumberOfSpaces, 2, (11 - k64)) \ + f((kNumberOfSpaces + 1), 2, 0) \ + f((kNumberOfSpaces + 2), 2, (142 - 16 * k64)) \ + f((kNumberOfSpaces + 3), 2, (74 - 15 * k64)) \ + f((kNumberOfSpaces + 4), 2, 5) \ + f((kNumberOfSpaces + 5), 1, 135) \ + f((kNumberOfSpaces + 6), 2, (228 - 39 * k64)) + +#define COMMON_RAW_LENGTHS(f) \ + f(1, 1) \ + f(2, 2) \ + f(3, 3) \ + f(4, 4) \ + f(5, 5) \ + f(6, 6) \ + f(7, 7) \ + f(8, 8) \ + f(9, 12) \ + f(10, 16) \ + f(11, 20) \ + f(12, 24) \ + f(13, 28) \ + f(14, 32) \ + f(15, 36) + +// The Serializer/Deserializer class is a common superclass for Serializer and +// Deserializer which is used to store common constants and methods used by +// both. +class SerializerDeserializer: public ObjectVisitor { + public: + RLYSTC void Iterate(ObjectVisitor* visitor); + RLYSTC void SetSnapshotCacheSize(int size); + + protected: + // Where the pointed-to object can be found: + enum Where { + kNewObject = 0, // Object is next in snapshot. + // 1-8 One per space. + kRootArray = 0x9, // Object is found in root array. + kPartialSnapshotCache = 0xa, // Object is in the cache. + kExternalReference = 0xb, // Pointer to an external reference. + // 0xc-0xf Free. + kBackref = 0x10, // Object is described relative to end. + // 0x11-0x18 One per space. + // 0x19-0x1f Common backref offsets. + kFromStart = 0x20, // Object is described relative to start. + // 0x21-0x28 One per space. + // 0x29-0x2f Free. + // 0x30-0x3f Used by misc tags below. + kPointedToMask = 0x3f + }; + + // How to code the pointer to the object. + enum HowToCode { + kPlain = 0, // Straight pointer. + // What this means depends on the architecture: + kFromCode = 0x40, // A pointer inlined in code. + kHowToCodeMask = 0x40 + }; + + // Where to point within the object. + enum WhereToPoint { + kStartOfObject = 0, + kFirstInstruction = 0x80, + kWhereToPointMask = 0x80 + }; + + // Misc. + // Raw data to be copied from the snapshot. + RLYSTC const int kRawData = 0x30; + // Some common raw lengths: 0x31-0x3f + // A tag emitted at strategic points in the snapshot to delineate sections. + // If the deserializer does not find these at the expected moments then it + // is an indication that the snapshot and the VM do not fit together. + // Examine the build process for architecture, version or configuration + // mismatches. + RLYSTC const int kSynchronize = 0x70; + // Used for the source code of the natives, which is in the executable, but + // is referred to from external strings in the snapshot. + RLYSTC const int kNativesStringResource = 0x71; + RLYSTC const int kNewPage = 0x72; + // 0x73-0x7f Free. + // 0xb0-0xbf Free. + // 0xf0-0xff Free. + + + RLYSTC const int kLargeData = LAST_SPACE; + RLYSTC const int kLargeCode = kLargeData + 1; + RLYSTC const int kLargeFixedArray = kLargeCode + 1; + RLYSTC const int kNumberOfSpaces = kLargeFixedArray + 1; + RLYSTC const int kAnyOldSpace = -1; + + // A bitmask for getting the space out of an instruction. + RLYSTC const int kSpaceMask = 15; + + RLYSTC inline bool SpaceIsLarge(int space) { return space >= kLargeData; } + RLYSTC inline bool SpaceIsPaged(int space) { + return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE; + } +}; + + +int SnapshotByteSource::GetInt() { + // A little unwind to catch the really small ints. + int snapshot_byte = Get(); + if ((snapshot_byte & 0x80) == 0) { + return snapshot_byte; + } + int accumulator = (snapshot_byte & 0x7f) << 7; + while (true) { + snapshot_byte = Get(); + if ((snapshot_byte & 0x80) == 0) { + return accumulator | snapshot_byte; + } + accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7; + } + UNREACHABLE(); + return accumulator; +} + + +void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) { + memcpy(to, data_ + position_, number_of_bytes); + position_ += number_of_bytes; +} + + +// A Deserializer reads a snapshot and reconstructs the Object graph it defines. +class Deserializer: public SerializerDeserializer { + public: + // Create a deserializer from a snapshot byte source. + explicit Deserializer(SnapshotByteSource* source); + + virtual ~Deserializer(); + + // Deserialize the snapshot into an empty heap. + void Deserialize(); + + // Deserialize a single object and the objects reachable from it. + void DeserializePartial(Object** root); + +#ifdef DEBUG + virtual void Synchronize(const char* tag); +#endif + + private: + virtual void VisitPointers(Object** start, Object** end); + + virtual void VisitExternalReferences(Address* start, Address* end) { + UNREACHABLE(); + } + + virtual void VisitRuntimeEntry(RelocInfo* rinfo) { + UNREACHABLE(); + } + + void ReadChunk(Object** start, Object** end, int space, Address address); + HeapObject* GetAddressFromStart(int space); + inline HeapObject* GetAddressFromEnd(int space); + Address Allocate(int space_number, Space* space, int size); + void ReadObject(int space_number, Space* space, Object** write_back); + + // Cached current isolate. + Isolate* isolate_; + + // Keep track of the pages in the paged spaces. + // (In large object space we are keeping track of individual objects + // rather than pages.) In new space we just need the address of the + // first object and the others will flow from that. + List<Address> pages_[SerializerDeserializer::kNumberOfSpaces]; + + SnapshotByteSource* source_; + // This is the address of the next object that will be allocated in each + // space. It is used to calculate the addresses of back-references. + Address high_water_[LAST_SPACE + 1]; + // This is the address of the most recent object that was allocated. It + // is used to set the location of the new page when we encounter a + // START_NEW_PAGE_SERIALIZATION tag. + Address last_object_address_; + + ExternalReferenceDecoder* external_reference_decoder_; + + DISALLOW_COPY_AND_ASSIGN(Deserializer); +}; + + +class SnapshotByteSink { + public: + virtual ~SnapshotByteSink() { } + virtual void Put(int byte, const char* description) = 0; + virtual void PutSection(int byte, const char* description) { + Put(byte, description); + } + void PutInt(uintptr_t integer, const char* description); + virtual int Position() = 0; +}; + + +// Mapping objects to their location after deserialization. +// This is used during building, but not at runtime by V8. +class SerializationAddressMapper { + public: + SerializationAddressMapper() + : serialization_map_(new HashMap(&SerializationMatchFun)), + no_allocation_(new AssertNoAllocation()) { } + + ~SerializationAddressMapper() { + delete serialization_map_; + delete no_allocation_; + } + + bool IsMapped(HeapObject* obj) { + return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL; + } + + int MappedTo(HeapObject* obj) { + ASSERT(IsMapped(obj)); + return static_cast<int>(reinterpret_cast<intptr_t>( + serialization_map_->Lookup(Key(obj), Hash(obj), false)->value)); + } + + void AddMapping(HeapObject* obj, int to) { + ASSERT(!IsMapped(obj)); + HashMap::Entry* entry = + serialization_map_->Lookup(Key(obj), Hash(obj), true); + entry->value = Value(to); + } + + private: + RLYSTC bool SerializationMatchFun(void* key1, void* key2) { + return key1 == key2; + } + + RLYSTC uint32_t Hash(HeapObject* obj) { + return static_cast<int32_t>(reinterpret_cast<intptr_t>(obj->address())); + } + + RLYSTC void* Key(HeapObject* obj) { + return reinterpret_cast<void*>(obj->address()); + } + + RLYSTC void* Value(int v) { + return reinterpret_cast<void*>(v); + } + + HashMap* serialization_map_; + AssertNoAllocation* no_allocation_; + DISALLOW_COPY_AND_ASSIGN(SerializationAddressMapper); +}; + + +// There can be only one serializer per V8 process. +STATIC_CLASS Serializer : public SerializerDeserializer { + public: + explicit Serializer(SnapshotByteSink* sink); + ~Serializer(); + void VisitPointers(Object** start, Object** end); + // You can call this after serialization to find out how much space was used + // in each space. + int CurrentAllocationAddress(int space) { + if (SpaceIsLarge(space)) return large_object_total_; + return fullness_[space]; + } + + RLYSTC void Enable() { + if (!serialization_enabled_) { + ASSERT(!too_late_to_enable_now_); + } + serialization_enabled_ = true; + } + + RLYSTC void Disable() { serialization_enabled_ = false; } + // Call this when you have made use of the fact that there is no serialization + // going on. + RLYSTC void TooLateToEnableNow() { too_late_to_enable_now_ = true; } + RLYSTC bool enabled() { return serialization_enabled_; } + SerializationAddressMapper* address_mapper() { return &address_mapper_; } +#ifdef DEBUG + virtual void Synchronize(const char* tag); +#endif + + protected: + RLYSTC const int kInvalidRootIndex = -1; + virtual int RootIndex(HeapObject* heap_object) = 0; + virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0; + + class ObjectSerializer : public ObjectVisitor { + public: + ObjectSerializer(Serializer* serializer, + Object* o, + SnapshotByteSink* sink, + HowToCode how_to_code, + WhereToPoint where_to_point) + : serializer_(serializer), + object_(HeapObject::cast(o)), + sink_(sink), + reference_representation_(how_to_code + where_to_point), + bytes_processed_so_far_(0) { } + void Serialize(); + void VisitPointers(Object** start, Object** end); + void VisitExternalReferences(Address* start, Address* end); + void VisitCodeTarget(RelocInfo* target); + void VisitCodeEntry(Address entry_address); + void VisitGlobalPropertyCell(RelocInfo* rinfo); + void VisitRuntimeEntry(RelocInfo* reloc); + // Used for seralizing the external strings that hold the natives source. + void VisitExternalAsciiString( + v8::String::ExternalAsciiStringResource** resource); + // We can't serialize a heap with external two byte strings. + void VisitExternalTwoByteString( + v8::String::ExternalStringResource** resource) { + UNREACHABLE(); + } + + private: + void OutputRawData(Address up_to); + + Serializer* serializer_; + HeapObject* object_; + SnapshotByteSink* sink_; + int reference_representation_; + int bytes_processed_so_far_; + }; + + virtual void SerializeObject(Object* o, + HowToCode how_to_code, + WhereToPoint where_to_point) = 0; + void SerializeReferenceToPreviousObject( + int space, + int address, + HowToCode how_to_code, + WhereToPoint where_to_point); + void InitializeAllocators(); + // This will return the space for an object. If the object is in large + // object space it may return kLargeCode or kLargeFixedArray in order + // to indicate to the deserializer what kind of large object allocation + // to make. + RLYSTC int SpaceOfObject(HeapObject* object); + // This just returns the space of the object. It will return LO_SPACE + // for all large objects since you can't check the type of the object + // once the map has been used for the serialization address. + RLYSTC int SpaceOfAlreadySerializedObject(HeapObject* object); + int Allocate(int space, int size, bool* new_page_started); + int EncodeExternalReference(Address addr) { + return external_reference_encoder_->Encode(addr); + } + + // Keep track of the fullness of each space in order to generate + // relative addresses for back references. Large objects are + // just numbered sequentially since relative addresses make no + // sense in large object space. + int fullness_[LAST_SPACE + 1]; + SnapshotByteSink* sink_; + int current_root_index_; + ExternalReferenceEncoder* external_reference_encoder_; + RLYSTC bool serialization_enabled_; + // Did we already make use of the fact that serialization was not enabled? + RLYSTC bool too_late_to_enable_now_; + int large_object_total_; + SerializationAddressMapper address_mapper_; + + friend class ObjectSerializer; + friend class Deserializer; + + DISALLOW_COPY_AND_ASSIGN(Serializer); +}; + + +class PartialSerializer : public Serializer { + public: + PartialSerializer(Serializer* startup_snapshot_serializer, + SnapshotByteSink* sink) + : Serializer(sink), + startup_serializer_(startup_snapshot_serializer) { + } + + // Serialize the objects reachable from a single object pointer. + virtual void Serialize(Object** o); + virtual void SerializeObject(Object* o, + HowToCode how_to_code, + WhereToPoint where_to_point); + + protected: + virtual int RootIndex(HeapObject* o); + virtual int PartialSnapshotCacheIndex(HeapObject* o); + virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) { + // Scripts should be referred only through shared function infos. We can't + // allow them to be part of the partial snapshot because they contain a + // unique ID, and deserializing several partial snapshots containing script + // would cause dupes. + ASSERT(!o->IsScript()); + return o->IsString() || o->IsSharedFunctionInfo() || + o->IsHeapNumber() || o->IsCode() || + o->map() == HEAP->fixed_cow_array_map(); + } + + private: + Serializer* startup_serializer_; + DISALLOW_COPY_AND_ASSIGN(PartialSerializer); +}; + + +class StartupSerializer : public Serializer { + public: + explicit StartupSerializer(SnapshotByteSink* sink) : Serializer(sink) { + // Clear the cache of objects used by the partial snapshot. After the + // strong roots have been serialized we can create a partial snapshot + // which will repopulate the cache with objects neede by that partial + // snapshot. + Isolate::Current()->set_serialize_partial_snapshot_cache_length(0); + } + // Serialize the current state of the heap. The order is: + // 1) Strong references. + // 2) Partial snapshot cache. + // 3) Weak references (eg the symbol table). + virtual void SerializeStrongReferences(); + virtual void SerializeObject(Object* o, + HowToCode how_to_code, + WhereToPoint where_to_point); + void SerializeWeakReferences(); + void Serialize() { + SerializeStrongReferences(); + SerializeWeakReferences(); + } + + private: + virtual int RootIndex(HeapObject* o) { return kInvalidRootIndex; } + virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) { + return false; + } +}; + + +} } // namespace v8::internal + +#endif // V8_SERIALIZE_H_ |