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:
parent
5c8d0d18f0
commit
ba8bbee634
195
src/serialize.cc
195
src/serialize.cc
@ -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());
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user