Revision: 3360
Author: [email protected]
Date: Wed Nov 25 04:55:33 2009
Log: Make heap serialization nondestructive.
Review URL: http://codereview.chromium.org/441017
http://code.google.com/p/v8/source/detail?r=3360
Modified:
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/serialize.cc
/branches/bleeding_edge/test/cctest/test-serialize.cc
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue Nov 24 06:10:06 2009
+++ /branches/bleeding_edge/src/objects-inl.h Wed Nov 25 04:55:33 2009
@@ -914,25 +914,6 @@
ASSERT(IsForwardingAddress());
return HeapObject::FromAddress(reinterpret_cast<Address>(value_));
}
-
-
-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() {
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Nov 24 06:10:06 2009
+++ /branches/bleeding_edge/src/objects.h Wed Nov 25 04:55:33 2009
@@ -830,16 +830,6 @@
// 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
=======================================
--- /branches/bleeding_edge/src/serialize.cc Fri Nov 20 04:38:59 2009
+++ /branches/bleeding_edge/src/serialize.cc Wed Nov 25 04:55:33 2009
@@ -44,6 +44,69 @@
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 @@
Heap::IterateRoots(this, VISIT_ONLY_STRONG);
delete external_reference_encoder_;
external_reference_encoder_ = NULL;
+ SerializationAddressMapper::Zap();
}
@@ -894,10 +958,9 @@
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 @@
}
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 @@
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) {
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Mon Nov 16
04:08:40 2009
+++ /branches/bleeding_edge/test/cctest/test-serialize.cc Wed Nov 25
04:55:33 2009
@@ -190,6 +190,15 @@
v8::V8::Initialize();
Serialize();
}
+
+
+// Test that heap serialization is non-destructive.
+TEST(SerializeTwice) {
+ Serializer::Enable();
+ v8::V8::Initialize();
+ Serialize();
+ Serialize();
+}
//----------------------------------------------------------------------------
@@ -218,7 +227,17 @@
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();
@@ -240,6 +259,22 @@
v8::Local<v8::Script> script = v8::Script::Compile(source);
CHECK_EQ(4, script->Run()->Int32Value());
}
+
+
+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) {
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---