summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/src/serialize.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/src/serialize.h')
-rw-r--r--src/3rdparty/v8/src/serialize.h589
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_