Commit 10e183d3 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Make heap serialization nondestructive.

Review URL: http://codereview.chromium.org/441017

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3360 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 059b9bbc
......@@ -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;
}
......
......@@ -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
......
......@@ -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 @@ 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) {
......
......@@ -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) {
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment