Make heap serialization nondestructive.
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 25 Nov 2009 12:55:33 +0000 (12:55 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 25 Nov 2009 12:55:33 +0000 (12:55 +0000)
Review URL: http://codereview.chromium.org/441017

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3360 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/objects-inl.h
src/objects.h
src/serialize.cc
test/cctest/test-serialize.cc

index ba5f5da..cf614d2 100644 (file)
@@ -916,25 +916,6 @@ HeapObject* MapWord::ToForwardingAddress() {
 }
 
 
-bool MapWord::IsSerializationAddress() {
-  return HAS_SMI_TAG(reinterpret_cast<Object*>(value_));
-}
-
-
-MapWord MapWord::FromSerializationAddress(int raw) {
-  // When the map word is being used as a serialization address we Smi-encode
-  // the serialization address (which is always a smallish positive integer).
-  return MapWord(reinterpret_cast<uintptr_t>(Smi::FromInt(raw)));
-}
-
-
-int MapWord::ToSerializationAddress() {
-  // When the map word is being used as a serialization address we treat the
-  // map word as a Smi and get the small integer that it encodes.
-  return reinterpret_cast<Smi*>(value_)->value();
-}
-
-
 bool MapWord::IsMarked() {
   return (value_ & kMarkingMask) == 0;
 }
index 00ebc0e..b96ec4f 100644 (file)
@@ -830,16 +830,6 @@ class MapWord BASE_EMBEDDED {
   // View this map word as a forwarding address.
   inline HeapObject* ToForwardingAddress();
 
-  // True if this map word is a serialization address.  This will only be the
-  // case during a destructive serialization of the heap.
-  inline bool IsSerializationAddress();
-
-  // Create a map word from a serialization address.
-  static inline MapWord FromSerializationAddress(int raw);
-
-  // View this map word as a serialization address.
-  inline int ToSerializationAddress();
-
   // Marking phase of full collection: the map word of live objects is
   // marked, and may be marked as overflowed (eg, the object is live, its
   // children have not been visited, and it does not fit in the marking
index 00cd69e..f505da2 100644 (file)
 namespace v8 {
 namespace internal {
 
+// Mapping objects to their location after deserialization.
+// This is used during building, but not at runtime by V8.
+class SerializationAddressMapper {
+ public:
+  static bool IsMapped(HeapObject* obj) {
+    EnsureMapExists();
+    return serialization_map_->Lookup(Key(obj), Hash(obj), false) != NULL;
+  }
+
+  static int MappedTo(HeapObject* obj) {
+    ASSERT(IsMapped(obj));
+    return reinterpret_cast<int>(serialization_map_->Lookup(Key(obj),
+                                 Hash(obj),
+                                 false)->value);
+  }
+
+  static void Map(HeapObject* obj, int to) {
+    EnsureMapExists();
+    ASSERT(!IsMapped(obj));
+    HashMap::Entry* entry =
+        serialization_map_->Lookup(Key(obj), Hash(obj), true);
+    entry->value = Value(to);
+  }
+
+  static void Zap() {
+    if (serialization_map_ != NULL) {
+      delete serialization_map_;
+    }
+    serialization_map_ = NULL;
+  }
+
+ private:
+  static bool SerializationMatchFun(void* key1, void* key2) {
+    return key1 == key2;
+  }
+
+  static uint32_t Hash(HeapObject* obj) {
+    return reinterpret_cast<uint32_t>(obj->address());
+  }
+
+  static void* Key(HeapObject* obj) {
+    return reinterpret_cast<void*>(obj->address());
+  }
+
+  static void* Value(int v) {
+    return reinterpret_cast<void*>(v);
+  }
+
+  static void EnsureMapExists() {
+    if (serialization_map_ == NULL) {
+      serialization_map_ = new HashMap(&SerializationMatchFun);
+    }
+  }
+
+  static HashMap* serialization_map_;
+};
+
+
+HashMap* SerializationAddressMapper::serialization_map_ = NULL;
+
+
+
+
 // -----------------------------------------------------------------------------
 // Coding of external references.
 
@@ -871,6 +934,7 @@ void Serializer::Serialize() {
   Heap::IterateRoots(this, VISIT_ONLY_STRONG);
   delete external_reference_encoder_;
   external_reference_encoder_ = NULL;
+  SerializationAddressMapper::Zap();
 }
 
 
@@ -894,10 +958,9 @@ void Serializer::SerializeObject(
     ReferenceRepresentation reference_representation) {
   CHECK(o->IsHeapObject());
   HeapObject* heap_object = HeapObject::cast(o);
-  MapWord map_word = heap_object->map_word();
-  if (map_word.IsSerializationAddress()) {
+  if (SerializationAddressMapper::IsMapped(heap_object)) {
     int space = SpaceOfAlreadySerializedObject(heap_object);
-    int address = map_word.ToSerializationAddress();
+    int address = SerializationAddressMapper::MappedTo(heap_object);
     int offset = CurrentAllocationAddress(space) - address;
     bool from_start = true;
     if (SpaceIsPaged(space)) {
@@ -965,24 +1028,23 @@ void Serializer::ObjectSerializer::Serialize() {
   }
   sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
 
-  // Get the map before overwriting it.
-  Map* map = object_->map();
   // Mark this object as already serialized.
   bool start_new_page;
-  object_->set_map_word(MapWord::FromSerializationAddress(
-      serializer_->Allocate(space, size, &start_new_page)));
+  SerializationAddressMapper::Map(
+    object_,
+    serializer_->Allocate(space, size, &start_new_page));
   if (start_new_page) {
     sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
     sink_->PutSection(space, "NewPageSpace");
   }
 
   // Serialize the map (first word of the object).
-  serializer_->SerializeObject(map, TAGGED_REPRESENTATION);
+  serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
 
   // Serialize the rest of the object.
   CHECK_EQ(0, bytes_processed_so_far_);
   bytes_processed_so_far_ = kPointerSize;
-  object_->IterateBody(map->instance_type(), size, this);
+  object_->IterateBody(object_->map()->instance_type(), size, this);
   OutputRawData(object_->address() + size);
 }
 
@@ -1044,12 +1106,9 @@ void Serializer::ObjectSerializer::VisitExternalAsciiString(
   Address references_start = reinterpret_cast<Address>(resource_pointer);
   OutputRawData(references_start);
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
-    // Use raw_unchecked when maps are munged.
-    Object* source = Heap::raw_unchecked_natives_source_cache()->get(i);
+    Object* source = Heap::natives_source_cache()->get(i);
     if (!source->IsUndefined()) {
-      // Don't use cast when maps are munged.
-      ExternalAsciiString* string =
-          reinterpret_cast<ExternalAsciiString*>(source);
+      ExternalAsciiString* string = ExternalAsciiString::cast(source);
       typedef v8::String::ExternalAsciiStringResource Resource;
       Resource* resource = string->resource();
       if (resource == *resource_pointer) {
index 9ed4874..8f4441a 100644 (file)
@@ -192,6 +192,15 @@ TEST(Serialize) {
 }
 
 
+// Test that heap serialization is non-destructive.
+TEST(SerializeTwice) {
+  Serializer::Enable();
+  v8::V8::Initialize();
+  Serialize();
+  Serialize();
+}
+
+
 //----------------------------------------------------------------------------
 // Tests that the heap can be deserialized.
 
@@ -218,7 +227,17 @@ DEPENDENT_TEST(Deserialize, Serialize) {
 
   Deserialize();
 
-  fflush(stdout);
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  SanityCheck();
+}
+
+
+DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
+  v8::HandleScope scope;
+
+  Deserialize();
 
   v8::Persistent<v8::Context> env = v8::Context::New();
   env->Enter();
@@ -242,6 +261,22 @@ DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
 }
 
 
+DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
+               SerializeTwice) {
+  v8::HandleScope scope;
+
+  Deserialize();
+
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  const char* c_source = "\"1234\".length";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  CHECK_EQ(4, script->Run()->Int32Value());
+}
+
+
 TEST(TestThatAlwaysSucceeds) {
 }