Serialize builtins by referencing canonical ones.

R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/383173002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22371 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-07-14 11:22:03 +00:00
parent 5c8d0d18f0
commit ba8bbee634
4 changed files with 189 additions and 137 deletions

View File

@ -889,83 +889,88 @@ void Deserializer::ReadChunk(Object** current,
STATIC_ASSERT((space_number & ~kSpaceMask) == 0);
#define CASE_BODY(where, how, within, space_number_if_any) \
{ \
bool emit_write_barrier = false; \
bool current_was_incremented = false; \
int space_number = space_number_if_any == kAnyOldSpace ? \
(data & kSpaceMask) : space_number_if_any; \
if (where == kNewObject && how == kPlain && within == kStartOfObject) {\
ReadObject(space_number, current); \
emit_write_barrier = (space_number == NEW_SPACE); \
} else { \
Object* new_object = NULL; /* May not be a real Object pointer. */ \
if (where == kNewObject) { \
ReadObject(space_number, &new_object); \
} else if (where == kRootArray) { \
int root_id = source_->GetInt(); \
new_object = isolate->heap()->roots_array_start()[root_id]; \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kPartialSnapshotCache) { \
int cache_index = source_->GetInt(); \
new_object = isolate->serialize_partial_snapshot_cache() \
[cache_index]; \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kExternalReference) { \
int skip = source_->GetInt(); \
current = reinterpret_cast<Object**>(reinterpret_cast<Address>( \
current) + skip); \
int reference_id = source_->GetInt(); \
Address address = external_reference_decoder_-> \
Decode(reference_id); \
new_object = reinterpret_cast<Object*>(address); \
} else if (where == kBackref) { \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromEnd(data & kSpaceMask); \
} else { \
ASSERT(where == kBackrefWithSkip); \
int skip = source_->GetInt(); \
current = reinterpret_cast<Object**>( \
reinterpret_cast<Address>(current) + skip); \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromEnd(data & kSpaceMask); \
} \
if (within == kInnerPointer) { \
if (space_number != CODE_SPACE || new_object->IsCode()) { \
Code* new_code_object = reinterpret_cast<Code*>(new_object); \
new_object = reinterpret_cast<Object*>( \
new_code_object->instruction_start()); \
} else { \
ASSERT(space_number == CODE_SPACE); \
Cell* cell = Cell::cast(new_object); \
new_object = reinterpret_cast<Object*>( \
cell->ValueAddress()); \
} \
} \
if (how == kFromCode) { \
Address location_of_branch_data = \
reinterpret_cast<Address>(current); \
Assembler::deserialization_set_special_target_at( \
location_of_branch_data, \
Code::cast(HeapObject::FromAddress(current_object_address)), \
reinterpret_cast<Address>(new_object)); \
location_of_branch_data += Assembler::kSpecialTargetSize; \
current = reinterpret_cast<Object**>(location_of_branch_data); \
current_was_incremented = true; \
} else { \
*current = new_object; \
} \
} \
if (emit_write_barrier && write_barrier_needed) { \
Address current_address = reinterpret_cast<Address>(current); \
isolate->heap()->RecordWrite( \
current_object_address, \
static_cast<int>(current_address - current_object_address)); \
} \
if (!current_was_incremented) { \
current++; \
} \
break; \
{ \
bool emit_write_barrier = false; \
bool current_was_incremented = false; \
int space_number = space_number_if_any == kAnyOldSpace \
? (data & kSpaceMask) \
: space_number_if_any; \
if (where == kNewObject && how == kPlain && within == kStartOfObject) { \
ReadObject(space_number, current); \
emit_write_barrier = (space_number == NEW_SPACE); \
} else { \
Object* new_object = NULL; /* May not be a real Object pointer. */ \
if (where == kNewObject) { \
ReadObject(space_number, &new_object); \
} else if (where == kRootArray) { \
int root_id = source_->GetInt(); \
new_object = isolate->heap()->roots_array_start()[root_id]; \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kPartialSnapshotCache) { \
int cache_index = source_->GetInt(); \
new_object = isolate->serialize_partial_snapshot_cache()[cache_index]; \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else if (where == kExternalReference) { \
int skip = source_->GetInt(); \
current = reinterpret_cast<Object**>( \
reinterpret_cast<Address>(current) + skip); \
int reference_id = source_->GetInt(); \
Address address = external_reference_decoder_->Decode(reference_id); \
new_object = reinterpret_cast<Object*>(address); \
} else if (where == kBackref) { \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromEnd(data & kSpaceMask); \
} else if (where == kBuiltin) { \
int builtin_id = source_->GetInt(); \
ASSERT_LE(0, builtin_id); \
ASSERT_LT(builtin_id, Builtins::builtin_count); \
Builtins::Name name = static_cast<Builtins::Name>(builtin_id); \
new_object = isolate->builtins()->builtin(name); \
emit_write_barrier = false; \
PrintF("BUILTIN how within %d, %d\n", how, within); \
} else { \
ASSERT(where == kBackrefWithSkip); \
int skip = source_->GetInt(); \
current = reinterpret_cast<Object**>( \
reinterpret_cast<Address>(current) + skip); \
emit_write_barrier = (space_number == NEW_SPACE); \
new_object = GetAddressFromEnd(data & kSpaceMask); \
} \
if (within == kInnerPointer) { \
if (space_number != CODE_SPACE || new_object->IsCode()) { \
Code* new_code_object = reinterpret_cast<Code*>(new_object); \
new_object = \
reinterpret_cast<Object*>(new_code_object->instruction_start()); \
} else { \
ASSERT(space_number == CODE_SPACE); \
Cell* cell = Cell::cast(new_object); \
new_object = reinterpret_cast<Object*>(cell->ValueAddress()); \
} \
} \
if (how == kFromCode) { \
Address location_of_branch_data = reinterpret_cast<Address>(current); \
Assembler::deserialization_set_special_target_at( \
location_of_branch_data, \
Code::cast(HeapObject::FromAddress(current_object_address)), \
reinterpret_cast<Address>(new_object)); \
location_of_branch_data += Assembler::kSpecialTargetSize; \
current = reinterpret_cast<Object**>(location_of_branch_data); \
current_was_incremented = true; \
} else { \
*current = new_object; \
} \
} \
if (emit_write_barrier && write_barrier_needed) { \
Address current_address = reinterpret_cast<Address>(current); \
isolate->heap()->RecordWrite( \
current_object_address, \
static_cast<int>(current_address - current_object_address)); \
} \
if (!current_was_incremented) { \
current++; \
} \
break; \
}
// This generates a case and a body for the new space (which has to do extra
// write barrier handling) and handles the other spaces with 8 fall-through
@ -1161,6 +1166,12 @@ void Deserializer::ReadChunk(Object** current,
kFromCode,
kStartOfObject,
0)
// Find a builtin and write a pointer to it to the current object.
CASE_STATEMENT(kBuiltin, kPlain, kStartOfObject, 0)
CASE_BODY(kBuiltin, kPlain, kStartOfObject, 0)
// Find a builtin and write a pointer to it in the current code object.
CASE_STATEMENT(kBuiltin, kFromCode, kInnerPointer, 0)
CASE_BODY(kBuiltin, kFromCode, kInnerPointer, 0)
#undef CASE_STATEMENT
#undef CASE_BODY
@ -1717,7 +1728,7 @@ int Serializer::ObjectSerializer::OutputRawData(
int up_to_offset = static_cast<int>(up_to - object_start);
int to_skip = up_to_offset - bytes_processed_so_far_;
int bytes_to_output = to_skip;
bytes_processed_so_far_ += to_skip;
bytes_processed_so_far_ += to_skip;
// This assert will fail if the reloc info gives us the target_address_address
// locations in a non-ascending order. Luckily that doesn't happen.
ASSERT(to_skip >= 0);
@ -1846,7 +1857,6 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
return;
}
// TODO(yangguo) wire up builtins.
// TODO(yangguo) wire up stubs from stub cache.
// TODO(yangguo) wire up script source.
// TODO(yangguo) wire up internalized strings
@ -1854,6 +1864,14 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
// TODO(yangguo) We cannot deal with different hash seeds yet.
ASSERT(!heap_object->IsHashTable());
if (heap_object->IsCode()) {
Code* code_object = Code::cast(heap_object);
if (code_object->kind() == Code::BUILTIN) {
SerializeBuiltin(code_object, how_to_code, where_to_point, skip);
return;
}
}
if (address_mapper_.IsMapped(heap_object)) {
int space = SpaceOfObject(heap_object);
int address = address_mapper_.MappedTo(heap_object);
@ -1873,6 +1891,27 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
}
void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
if (skip != 0) {
sink_->Put(kSkip, "SkipFromSerializeBuiltin");
sink_->PutInt(skip, "SkipDistanceFromSerializeBuiltin");
}
ASSERT((how_to_code == kPlain && where_to_point == kStartOfObject) ||
(how_to_code == kFromCode && where_to_point == kInnerPointer));
int id = 0;
do { // Look for existing builtins in the list.
Code* b = isolate()->builtins()->builtin(static_cast<Builtins::Name>(id));
if (builtin == b) break;
} while (++id < Builtins::builtin_count);
ASSERT(id < Builtins::builtin_count); // We must have found a one.
sink_->Put(kBuiltin + how_to_code + where_to_point, "Builtin");
sink_->PutInt(id, "builtin_index");
}
Object* CodeSerializer::Deserialize(Isolate* isolate, ScriptData* data) {
SerializedCodeData scd(data);
SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());

View File

@ -148,17 +148,18 @@ class SerializerDeserializer: public ObjectVisitor {
protected:
// Where the pointed-to object can be found:
enum Where {
kNewObject = 0, // Object is next in snapshot.
kNewObject = 0, // Object is next in snapshot.
// 1-6 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.
kSkip = 0xc, // Skip n bytes.
kNop = 0xd, // Does nothing, used to pad.
// 0xe-0xf Free.
kBackref = 0x10, // Object is described relative to end.
kRootArray = 0x9, // Object is found in root array.
kPartialSnapshotCache = 0xa, // Object is in the cache.
kExternalReference = 0xb, // Pointer to an external reference.
kSkip = 0xc, // Skip n bytes.
kBuiltin = 0xd, // Builtin code object.
// 0xe Free.
kNop = 0xf, // Does nothing, used to pad.
kBackref = 0x10, // Object is described relative to end.
// 0x11-0x16 One per space.
kBackrefWithSkip = 0x18, // Object is described relative to end.
kBackrefWithSkip = 0x18, // Object is described relative to end.
// 0x19-0x1e One per space.
// 0x20-0x3f Used by misc. tags below.
kPointedToMask = 0x3f
@ -566,14 +567,9 @@ class CodeSerializer : public Serializer {
static Object* Deserialize(Isolate* isolate, ScriptData* data);
// The data header consists of int-sized entries:
// [0] version hash
// [1] length in bytes
// [2..8] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
static const int kHeaderSize = 9;
static const int kVersionHashOffset = 0;
static const int kPayloadLengthOffset = 1;
static const int kReservationsOffset = 2;
private:
void SerializeBuiltin(Code* builtin, HowToCode how_to_code,
WhereToPoint where_to_point, int skip);
};

View File

@ -399,48 +399,6 @@ TEST(OptimizedCodeSharing) {
}
TEST(SerializeToplevel) {
FLAG_serialize_toplevel = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> context = CcTest::NewContext(PRINT_EXTENSION);
v8::Context::Scope context_scope(context);
const char* source1 = "1 + 1";
const char* source2 = "1 + 2"; // Use alternate string to verify caching.
Isolate* isolate = CcTest::i_isolate();
Handle<String> source1_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source1))
.ToHandleChecked();
Handle<String> source2_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source2))
.ToHandleChecked();
ScriptData* cache = NULL;
Handle<SharedFunctionInfo> orig =
Compiler::CompileScript(source1_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, PRODUCE_CACHED_DATA, NOT_NATIVES_CODE);
Handle<SharedFunctionInfo> info =
Compiler::CompileScript(source2_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, CONSUME_CACHED_DATA, NOT_NATIVES_CODE);
CHECK_NE(*orig, *info);
Handle<JSFunction> fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
info, isolate->native_context());
Handle<JSObject> global(isolate->context()->global_object());
Handle<Object> result =
Execution::Call(isolate, fun, global, 0, NULL).ToHandleChecked();
CHECK_EQ(2, Handle<Smi>::cast(result)->value());
delete cache;
}
#ifdef ENABLE_DISASSEMBLER
static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
const char* property_name) {

View File

@ -661,3 +661,62 @@ DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
bool ArtificialFailure2 = false;
CHECK(ArtificialFailure2);
}
int CountBuiltins() {
// Check that we have not deserialized any additional builtin.
HeapIterator iterator(CcTest::heap());
DisallowHeapAllocation no_allocation;
int counter = 0;
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++;
}
return counter;
}
TEST(SerializeToplevel) {
FLAG_serialize_toplevel = true;
v8::HandleScope scope(CcTest::isolate());
v8::Local<v8::Context> context = CcTest::NewContext(PRINT_EXTENSION);
v8::Context::Scope context_scope(context);
const char* source1 = "1 + 1";
const char* source2 = "1 + 2"; // Use alternate string to verify caching.
Isolate* isolate = CcTest::i_isolate();
Handle<String> source1_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source1))
.ToHandleChecked();
Handle<String> source2_string = isolate->factory()
->NewStringFromUtf8(CStrVector(source2))
.ToHandleChecked();
ScriptData* cache = NULL;
Handle<SharedFunctionInfo> orig =
Compiler::CompileScript(source1_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, PRODUCE_CACHED_DATA, NOT_NATIVES_CODE);
int builtins_count = CountBuiltins();
Handle<SharedFunctionInfo> info =
Compiler::CompileScript(source2_string, Handle<String>(), 0, 0, false,
Handle<Context>(isolate->native_context()), NULL,
&cache, CONSUME_CACHED_DATA, NOT_NATIVES_CODE);
CHECK_NE(*orig, *info);
Handle<JSFunction> fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
info, isolate->native_context());
Handle<JSObject> global(isolate->context()->global_object());
Handle<Object> result =
Execution::Call(isolate, fun, global, 0, NULL).ToHandleChecked();
CHECK_EQ(2, Handle<Smi>::cast(result)->value());
CHECK_EQ(builtins_count, CountBuiltins());
delete cache;
}