summaryrefslogtreecommitdiff
path: root/deps/v8/src/serialize.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/serialize.cc')
-rw-r--r--deps/v8/src/serialize.cc411
1 files changed, 287 insertions, 124 deletions
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index 4b28d23fe9..9d59b6fd4f 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -8,17 +8,18 @@
#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/global-handles.h"
-#include "src/ic-inl.h"
+#include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
#include "src/natives.h"
#include "src/objects.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
#include "src/serialize.h"
#include "src/snapshot.h"
#include "src/snapshot-source-sink.h"
-#include "src/stub-cache.h"
#include "src/v8threads.h"
#include "src/version.h"
@@ -314,7 +315,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
#undef IC_ENTRY
}; // end of ref_table[].
- for (size_t i = 0; i < ARRAY_SIZE(ref_table); ++i) {
+ for (size_t i = 0; i < arraysize(ref_table); ++i) {
AddFromId(ref_table[i].type,
ref_table[i].id,
ref_table[i].name,
@@ -340,7 +341,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
}; // end of stats_ref_table[].
Counters* counters = isolate->counters();
- for (size_t i = 0; i < ARRAY_SIZE(stats_ref_table); ++i) {
+ for (size_t i = 0; i < arraysize(stats_ref_table); ++i) {
Add(reinterpret_cast<Address>(GetInternalPointer(
(counters->*(stats_ref_table[i].counter))())),
STATS_COUNTER,
@@ -595,8 +596,9 @@ Deserializer::Deserializer(SnapshotByteSource* source)
: isolate_(NULL),
attached_objects_(NULL),
source_(source),
- external_reference_decoder_(NULL) {
- for (int i = 0; i < LAST_SPACE + 1; i++) {
+ external_reference_decoder_(NULL),
+ deserialized_large_objects_(0) {
+ for (int i = 0; i < kNumberOfSpaces; i++) {
reservations_[i] = kUninitializedReservation;
}
}
@@ -614,7 +616,7 @@ void Deserializer::FlushICacheForNewCodeObjects() {
void Deserializer::Deserialize(Isolate* isolate) {
isolate_ = isolate;
DCHECK(isolate_ != NULL);
- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+ isolate_->heap()->ReserveSpace(reservations_, high_water_);
// No active threads.
DCHECK_EQ(NULL, isolate_->thread_manager()->FirstThreadStateInUse());
// No active handles.
@@ -644,7 +646,7 @@ void Deserializer::Deserialize(Isolate* isolate) {
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
Object* source = isolate_->heap()->natives_source_cache()->get(i);
if (!source->IsUndefined()) {
- ExternalAsciiString::cast(source)->update_data_cache();
+ ExternalOneByteString::cast(source)->update_data_cache();
}
}
@@ -661,7 +663,8 @@ void Deserializer::DeserializePartial(Isolate* isolate, Object** root) {
for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
DCHECK(reservations_[i] != kUninitializedReservation);
}
- isolate_->heap()->ReserveSpace(reservations_, &high_water_[0]);
+ Heap* heap = isolate->heap();
+ heap->ReserveSpace(reservations_, high_water_);
if (external_reference_decoder_ == NULL) {
external_reference_decoder_ = new ExternalReferenceDecoder(isolate);
}
@@ -727,14 +730,14 @@ class StringTableInsertionKey : public HashTableKey {
return string_->SlowEquals(String::cast(string));
}
- virtual uint32_t Hash() V8_OVERRIDE { return hash_; }
+ virtual uint32_t Hash() OVERRIDE { return hash_; }
- virtual uint32_t HashForObject(Object* key) V8_OVERRIDE {
+ virtual uint32_t HashForObject(Object* key) OVERRIDE {
return String::cast(key)->Hash();
}
MUST_USE_RESULT virtual Handle<Object> AsHandle(Isolate* isolate)
- V8_OVERRIDE {
+ OVERRIDE {
return handle(string_, isolate);
}
@@ -797,11 +800,40 @@ void Deserializer::ReadObject(int space_number,
*write_back = obj;
#ifdef DEBUG
- bool is_codespace = (space_number == CODE_SPACE);
- DCHECK(obj->IsCode() == is_codespace);
+ if (obj->IsCode()) {
+ DCHECK(space_number == CODE_SPACE || space_number == LO_SPACE);
+ } else {
+ DCHECK(space_number != CODE_SPACE);
+ }
#endif
}
+
+// We know the space requirements before deserialization and can
+// pre-allocate that reserved space. During deserialization, all we need
+// to do is to bump up the pointer for each space in the reserved
+// space. This is also used for fixing back references.
+// Since multiple large objects cannot be folded into one large object
+// space allocation, we have to do an actual allocation when deserializing
+// each large object. Instead of tracking offset for back references, we
+// reference large objects by index.
+Address Deserializer::Allocate(int space_index, int size) {
+ if (space_index == LO_SPACE) {
+ AlwaysAllocateScope scope(isolate_);
+ LargeObjectSpace* lo_space = isolate_->heap()->lo_space();
+ Executability exec = static_cast<Executability>(source_->GetInt());
+ AllocationResult result = lo_space->AllocateRaw(size, exec);
+ HeapObject* obj = HeapObject::cast(result.ToObjectChecked());
+ deserialized_large_objects_.Add(obj);
+ return obj->address();
+ } else {
+ DCHECK(space_index < kNumberOfPreallocatedSpaces);
+ Address address = high_water_[space_index];
+ high_water_[space_index] = address + size;
+ return address;
+ }
+}
+
void Deserializer::ReadChunk(Object** current,
Object** limit,
int source_space,
@@ -872,7 +904,7 @@ void Deserializer::ReadChunk(Object** current,
} else if (where == kAttachedReference) { \
DCHECK(deserializing_user_code()); \
int index = source_->GetInt(); \
- new_object = attached_objects_->at(index); \
+ new_object = *attached_objects_->at(index); \
emit_write_barrier = isolate->heap()->InNewSpace(new_object); \
} else { \
DCHECK(where == kBackrefWithSkip); \
@@ -924,15 +956,16 @@ void Deserializer::ReadChunk(Object** current,
// 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
// cases and one body.
-#define ALL_SPACES(where, how, within) \
- CASE_STATEMENT(where, how, within, NEW_SPACE) \
- CASE_BODY(where, how, within, NEW_SPACE) \
- CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
- CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
- CASE_STATEMENT(where, how, within, CODE_SPACE) \
- CASE_STATEMENT(where, how, within, CELL_SPACE) \
- CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
- CASE_STATEMENT(where, how, within, MAP_SPACE) \
+#define ALL_SPACES(where, how, within) \
+ CASE_STATEMENT(where, how, within, NEW_SPACE) \
+ CASE_BODY(where, how, within, NEW_SPACE) \
+ CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \
+ CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \
+ CASE_STATEMENT(where, how, within, CODE_SPACE) \
+ CASE_STATEMENT(where, how, within, MAP_SPACE) \
+ CASE_STATEMENT(where, how, within, CELL_SPACE) \
+ CASE_STATEMENT(where, how, within, PROPERTY_CELL_SPACE) \
+ CASE_STATEMENT(where, how, within, LO_SPACE) \
CASE_BODY(where, how, within, kAnyOldSpace)
#define FOUR_CASES(byte_code) \
@@ -1087,6 +1120,12 @@ void Deserializer::ReadChunk(Object** current,
// current object.
CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
CASE_BODY(kRootArray, kPlain, kStartOfObject, 0)
+#if defined(V8_TARGET_ARCH_MIPS) || V8_OOL_CONSTANT_POOL || \
+ defined(V8_TARGET_ARCH_MIPS64)
+ // Find an object in the roots array and write a pointer to it to in code.
+ CASE_STATEMENT(kRootArray, kFromCode, kStartOfObject, 0)
+ CASE_BODY(kRootArray, kFromCode, kStartOfObject, 0)
+#endif
// Find an object in the partial snapshots cache and write a pointer to it
// to the current object.
CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
@@ -1118,6 +1157,12 @@ void Deserializer::ReadChunk(Object** current,
// 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)
+#if V8_OOL_CONSTANT_POOL
+ // Find a builtin code entry and write a pointer to it to the current
+ // object.
+ CASE_STATEMENT(kBuiltin, kPlain, kInnerPointer, 0)
+ CASE_BODY(kBuiltin, kPlain, kInnerPointer, 0)
+#endif
// 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)
@@ -1125,6 +1170,10 @@ void Deserializer::ReadChunk(Object** current,
// the current object.
CASE_STATEMENT(kAttachedReference, kPlain, kStartOfObject, 0)
CASE_BODY(kAttachedReference, kPlain, kStartOfObject, 0)
+ CASE_STATEMENT(kAttachedReference, kPlain, kInnerPointer, 0)
+ CASE_BODY(kAttachedReference, kPlain, kInnerPointer, 0)
+ CASE_STATEMENT(kAttachedReference, kFromCode, kInnerPointer, 0)
+ CASE_BODY(kAttachedReference, kFromCode, kInnerPointer, 0)
#undef CASE_STATEMENT
#undef CASE_BODY
@@ -1167,12 +1216,11 @@ Serializer::Serializer(Isolate* isolate, SnapshotByteSink* sink)
sink_(sink),
external_reference_encoder_(new ExternalReferenceEncoder(isolate)),
root_index_wave_front_(0),
- code_address_map_(NULL) {
+ code_address_map_(NULL),
+ seen_large_objects_index_(0) {
// The serializer is meant to be used only to generate initial heap images
// from a context in which there is only one isolate.
- for (int i = 0; i <= LAST_SPACE; i++) {
- fullness_[i] = 0;
- }
+ for (int i = 0; i < kNumberOfSpaces; i++) fullness_[i] = 0;
}
@@ -1291,15 +1339,6 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
for (int i = 0; i < root_index_wave_front_; i++) {
Object* root = heap->roots_array_start()[i];
if (!root->IsSmi() && root == heap_object) {
-#if defined(V8_TARGET_ARCH_MIPS) || V8_OOL_CONSTANT_POOL || \
- defined(V8_TARGET_ARCH_MIPS64)
- if (from == kFromCode) {
- // In order to avoid code bloat in the deserializer we don't have
- // support for the encoding that specifies a particular root should
- // be written from within code.
- return kInvalidRootIndex;
- }
-#endif
return i;
}
}
@@ -1311,15 +1350,12 @@ int Serializer::RootIndex(HeapObject* heap_object, HowToCode from) {
// location into a later object. We can encode the location as an offset from
// the start of the deserialized objects or as an offset backwards from the
// current allocation pointer.
-void Serializer::SerializeReferenceToPreviousObject(
- int space,
- int address,
- HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip) {
- int offset = CurrentAllocationAddress(space) - address;
- // Shift out the bits that are always 0.
- offset >>= kObjectAlignmentBits;
+void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object,
+ HowToCode how_to_code,
+ WhereToPoint where_to_point,
+ int skip) {
+ int space = SpaceOfObject(heap_object);
+
if (skip == 0) {
sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
} else {
@@ -1327,7 +1363,17 @@ void Serializer::SerializeReferenceToPreviousObject(
"BackRefSerWithSkip");
sink_->PutInt(skip, "BackRefSkipDistance");
}
- sink_->PutInt(offset, "offset");
+
+ if (space == LO_SPACE) {
+ int index = address_mapper_.MappedTo(heap_object);
+ sink_->PutInt(index, "large object index");
+ } else {
+ int address = address_mapper_.MappedTo(heap_object);
+ int offset = CurrentAllocationAddress(space) - address;
+ // Shift out the bits that are always 0.
+ offset >>= kObjectAlignmentBits;
+ sink_->PutInt(offset, "offset");
+ }
}
@@ -1347,12 +1393,7 @@ void StartupSerializer::SerializeObject(
}
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space,
- address,
- how_to_code,
- where_to_point,
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
skip);
} else {
if (skip != 0) {
@@ -1455,12 +1496,7 @@ void PartialSerializer::SerializeObject(
DCHECK(!heap_object->IsInternalizedString());
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space,
- address,
- how_to_code,
- where_to_point,
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
skip);
} else {
if (skip != 0) {
@@ -1496,8 +1532,18 @@ void Serializer::ObjectSerializer::Serialize() {
}
// Mark this object as already serialized.
- int offset = serializer_->Allocate(space, size);
- serializer_->address_mapper()->AddMapping(object_, offset);
+ if (space == LO_SPACE) {
+ if (object_->IsCode()) {
+ sink_->PutInt(EXECUTABLE, "executable large object");
+ } else {
+ sink_->PutInt(NOT_EXECUTABLE, "not executable large object");
+ }
+ int index = serializer_->AllocateLargeObject(size);
+ serializer_->address_mapper()->AddMapping(object_, index);
+ } else {
+ int offset = serializer_->Allocate(space, size);
+ serializer_->address_mapper()->AddMapping(object_, offset);
+ }
// Serialize the map (first word of the object).
serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject, 0);
@@ -1529,7 +1575,8 @@ void Serializer::ObjectSerializer::VisitPointers(Object** start,
current_contents == current[-1]) {
DCHECK(!serializer_->isolate()->heap()->InNewSpace(current_contents));
int repeat_count = 1;
- while (current < end - 1 && current[repeat_count] == current_contents) {
+ while (&current[repeat_count] < end - 1 &&
+ current[repeat_count] == current_contents) {
repeat_count++;
}
current += repeat_count;
@@ -1626,19 +1673,20 @@ void Serializer::ObjectSerializer::VisitCell(RelocInfo* rinfo) {
int skip = OutputRawData(rinfo->pc(), kCanReturnSkipInsteadOfSkipping);
Cell* object = Cell::cast(rinfo->target_cell());
serializer_->SerializeObject(object, kPlain, kInnerPointer, skip);
+ bytes_processed_so_far_ += kPointerSize;
}
-void Serializer::ObjectSerializer::VisitExternalAsciiString(
- v8::String::ExternalAsciiStringResource** resource_pointer) {
+void Serializer::ObjectSerializer::VisitExternalOneByteString(
+ v8::String::ExternalOneByteStringResource** resource_pointer) {
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
Object* source =
serializer_->isolate()->heap()->natives_source_cache()->get(i);
if (!source->IsUndefined()) {
- ExternalAsciiString* string = ExternalAsciiString::cast(source);
- typedef v8::String::ExternalAsciiStringResource Resource;
+ ExternalOneByteString* string = ExternalOneByteString::cast(source);
+ typedef v8::String::ExternalOneByteStringResource Resource;
const Resource* resource = string->resource();
if (resource == *resource_pointer) {
sink_->Put(kNativesStringResource, "NativesStringResource");
@@ -1747,8 +1795,14 @@ int Serializer::SpaceOfObject(HeapObject* object) {
}
+int Serializer::AllocateLargeObject(int size) {
+ fullness_[LO_SPACE] += size;
+ return seen_large_objects_index_++;
+}
+
+
int Serializer::Allocate(int space, int size) {
- CHECK(space >= 0 && space < kNumberOfSpaces);
+ CHECK(space >= 0 && space < kNumberOfPreallocatedSpaces);
int allocation_address = fullness_[space];
fullness_[space] = allocation_address + size;
return allocation_address;
@@ -1782,64 +1836,109 @@ void Serializer::InitializeCodeAddressMap() {
ScriptData* CodeSerializer::Serialize(Isolate* isolate,
Handle<SharedFunctionInfo> info,
Handle<String> source) {
+ base::ElapsedTimer timer;
+ if (FLAG_profile_deserialization) timer.Start();
+
// Serialize code object.
List<byte> payload;
ListSnapshotSink list_sink(&payload);
- CodeSerializer cs(isolate, &list_sink, *source);
+ DebugSnapshotSink debug_sink(&list_sink);
+ SnapshotByteSink* sink = FLAG_trace_code_serializer
+ ? static_cast<SnapshotByteSink*>(&debug_sink)
+ : static_cast<SnapshotByteSink*>(&list_sink);
+ CodeSerializer cs(isolate, sink, *source, info->code());
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
cs.VisitPointer(location);
cs.Pad();
SerializedCodeData data(&payload, &cs);
- return data.GetScriptData();
+ ScriptData* script_data = data.GetScriptData();
+
+ if (FLAG_profile_deserialization) {
+ double ms = timer.Elapsed().InMillisecondsF();
+ int length = script_data->length();
+ PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms);
+ }
+
+ return script_data;
}
void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) {
- CHECK(o->IsHeapObject());
HeapObject* heap_object = HeapObject::cast(o);
- // The code-caches link to context-specific code objects, which
- // the startup and context serializes cannot currently handle.
- DCHECK(!heap_object->IsMap() ||
- Map::cast(heap_object)->code_cache() ==
- heap_object->GetHeap()->empty_fixed_array());
-
int root_index;
if ((root_index = RootIndex(heap_object, how_to_code)) != kInvalidRootIndex) {
PutRoot(root_index, heap_object, how_to_code, where_to_point, skip);
return;
}
- // TODO(yangguo) wire up stubs from stub cache.
- // TODO(yangguo) wire up global object.
- // TODO(yangguo) We cannot deal with different hash seeds yet.
- DCHECK(!heap_object->IsHashTable());
-
if (address_mapper_.IsMapped(heap_object)) {
- int space = SpaceOfObject(heap_object);
- int address = address_mapper_.MappedTo(heap_object);
- SerializeReferenceToPreviousObject(space, address, how_to_code,
- where_to_point, skip);
+ SerializeReferenceToPreviousObject(heap_object, how_to_code, where_to_point,
+ skip);
return;
}
+ if (skip != 0) {
+ sink_->Put(kSkip, "SkipFromSerializeObject");
+ sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+ }
+
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;
+ switch (code_object->kind()) {
+ case Code::OPTIMIZED_FUNCTION: // No optimized code compiled yet.
+ case Code::HANDLER: // No handlers patched in yet.
+ case Code::REGEXP: // No regexp literals initialized yet.
+ case Code::NUMBER_OF_KINDS: // Pseudo enum value.
+ CHECK(false);
+ case Code::BUILTIN:
+ SerializeBuiltin(code_object, how_to_code, where_to_point);
+ return;
+ case Code::STUB:
+ SerializeCodeStub(code_object, how_to_code, where_to_point);
+ return;
+#define IC_KIND_CASE(KIND) case Code::KIND:
+ IC_KIND_LIST(IC_KIND_CASE)
+#undef IC_KIND_CASE
+ SerializeHeapObject(code_object, how_to_code, where_to_point);
+ return;
+ // TODO(yangguo): add special handling to canonicalize ICs.
+ case Code::FUNCTION:
+ // Only serialize the code for the toplevel function. Replace code
+ // of included function literals by the lazy compile builtin.
+ // This is safe, as checked in Compiler::BuildFunctionInfo.
+ if (code_object != main_code_) {
+ Code* lazy = *isolate()->builtins()->CompileLazy();
+ SerializeBuiltin(lazy, how_to_code, where_to_point);
+ } else {
+ SerializeHeapObject(code_object, how_to_code, where_to_point);
+ }
+ return;
}
- // TODO(yangguo) figure out whether other code kinds can be handled smarter.
}
if (heap_object == source_) {
- SerializeSourceObject(how_to_code, where_to_point, skip);
+ SerializeSourceObject(how_to_code, where_to_point);
return;
}
+ // Past this point we should not see any (context-specific) maps anymore.
+ CHECK(!heap_object->IsMap());
+ // There should be no references to the global object embedded.
+ CHECK(!heap_object->IsJSGlobalProxy() && !heap_object->IsGlobalObject());
+ // There should be no hash table embedded. They would require rehashing.
+ CHECK(!heap_object->IsHashTable());
+
+ SerializeHeapObject(heap_object, how_to_code, where_to_point);
+}
+
+
+void CodeSerializer::SerializeHeapObject(HeapObject* heap_object,
+ HowToCode how_to_code,
+ WhereToPoint where_to_point) {
if (heap_object->IsScript()) {
// The wrapper cache uses a Foreign object to point to a global handle.
// However, the object visitor expects foreign objects to point to external
@@ -1847,10 +1946,12 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code,
Script::cast(heap_object)->ClearWrapperCache();
}
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding heap object: ");
+ heap_object->ShortPrint();
+ PrintF("\n");
}
+
// Object has not yet been serialized. Serialize it here.
ObjectSerializer serializer(this, heap_object, sink_, how_to_code,
where_to_point);
@@ -1859,30 +1960,61 @@ 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");
- }
-
+ WhereToPoint where_to_point) {
DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
+ (how_to_code == kPlain && where_to_point == kInnerPointer) ||
(how_to_code == kFromCode && where_to_point == kInnerPointer));
int builtin_index = builtin->builtin_index();
DCHECK_LT(builtin_index, Builtins::builtin_count);
DCHECK_LE(0, builtin_index);
+
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding builtin: %s\n",
+ isolate()->builtins()->name(builtin_index));
+ }
+
sink_->Put(kBuiltin + how_to_code + where_to_point, "Builtin");
sink_->PutInt(builtin_index, "builtin_index");
}
-void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
- WhereToPoint where_to_point,
- int skip) {
- if (skip != 0) {
- sink_->Put(kSkip, "SkipFromSerializeSourceObject");
- sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject");
+void CodeSerializer::SerializeCodeStub(Code* stub, HowToCode how_to_code,
+ WhereToPoint where_to_point) {
+ DCHECK((how_to_code == kPlain && where_to_point == kStartOfObject) ||
+ (how_to_code == kPlain && where_to_point == kInnerPointer) ||
+ (how_to_code == kFromCode && where_to_point == kInnerPointer));
+ uint32_t stub_key = stub->stub_key();
+ DCHECK(CodeStub::MajorKeyFromKey(stub_key) != CodeStub::NoCache);
+
+ int index = AddCodeStubKey(stub_key) + kCodeStubsBaseIndex;
+
+ if (FLAG_trace_code_serializer) {
+ PrintF("Encoding code stub %s as %d\n",
+ CodeStub::MajorName(CodeStub::MajorKeyFromKey(stub_key), false),
+ index);
}
+ sink_->Put(kAttachedReference + how_to_code + where_to_point, "CodeStub");
+ sink_->PutInt(index, "CodeStub key");
+}
+
+
+int CodeSerializer::AddCodeStubKey(uint32_t stub_key) {
+ // TODO(yangguo) Maybe we need a hash table for a faster lookup than O(n^2).
+ int index = 0;
+ while (index < stub_keys_.length()) {
+ if (stub_keys_[index] == stub_key) return index;
+ index++;
+ }
+ stub_keys_.Add(stub_key);
+ return index;
+}
+
+
+void CodeSerializer::SerializeSourceObject(HowToCode how_to_code,
+ WhereToPoint where_to_point) {
+ if (FLAG_trace_code_serializer) PrintF("Encoding source object\n");
+
DCHECK(how_to_code == kPlain && where_to_point == kStartOfObject);
sink_->Put(kAttachedReference + how_to_code + where_to_point, "Source");
sink_->PutInt(kSourceObjectIndex, "kSourceObjectIndex");
@@ -1894,22 +2026,36 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
Handle<String> source) {
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
- SerializedCodeData scd(data, *source);
- SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
- Deserializer deserializer(&payload);
- STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- deserializer.set_reservation(i, scd.GetReservation(i));
- }
-
- // Prepare and register list of attached objects.
- Vector<Object*> attached_objects = Vector<Object*>::New(1);
- attached_objects[kSourceObjectIndex] = *source;
- deserializer.SetAttachedObjects(&attached_objects);
Object* root;
- deserializer.DeserializePartial(isolate, &root);
- deserializer.FlushICacheForNewCodeObjects();
+
+ {
+ HandleScope scope(isolate);
+
+ SerializedCodeData scd(data, *source);
+ SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
+ Deserializer deserializer(&payload);
+ STATIC_ASSERT(NEW_SPACE == 0);
+ for (int i = NEW_SPACE; i < kNumberOfSpaces; i++) {
+ deserializer.set_reservation(i, scd.GetReservation(i));
+ }
+
+ // Prepare and register list of attached objects.
+ Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys();
+ Vector<Handle<Object> > attached_objects = Vector<Handle<Object> >::New(
+ code_stub_keys.length() + kCodeStubsBaseIndex);
+ attached_objects[kSourceObjectIndex] = source;
+ for (int i = 0; i < code_stub_keys.length(); i++) {
+ attached_objects[i + kCodeStubsBaseIndex] =
+ CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked();
+ }
+ deserializer.SetAttachedObjects(&attached_objects);
+
+ // Deserialize.
+ deserializer.DeserializePartial(isolate, &root);
+ deserializer.FlushICacheForNewCodeObjects();
+ }
+
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
int length = data->length();
@@ -1922,18 +2068,35 @@ Handle<SharedFunctionInfo> CodeSerializer::Deserialize(Isolate* isolate,
SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
: owns_script_data_(true) {
DisallowHeapAllocation no_gc;
- int data_length = payload->length() + kHeaderEntries * kIntSize;
+ List<uint32_t>* stub_keys = cs->stub_keys();
+
+ // Calculate sizes.
+ int num_stub_keys = stub_keys->length();
+ int stub_keys_size = stub_keys->length() * kInt32Size;
+ int data_length = kHeaderSize + stub_keys_size + payload->length();
+
+ // Allocate backing store and create result data.
byte* data = NewArray<byte>(data_length);
DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
- CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
- static_cast<size_t>(payload->length()));
script_data_ = new ScriptData(data, data_length);
script_data_->AcquireDataOwnership();
+
+ // Set header values.
SetHeaderValue(kCheckSumOffset, CheckSum(cs->source()));
+ SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
+ SetHeaderValue(kPayloadLengthOffset, payload->length());
STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ for (int i = 0; i < SerializerDeserializer::kNumberOfSpaces; i++) {
SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
}
+
+ // Copy code stub keys.
+ CopyBytes(data + kHeaderSize, reinterpret_cast<byte*>(stub_keys->begin()),
+ stub_keys_size);
+
+ // Copy serialized data.
+ CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(),
+ static_cast<size_t>(payload->length()));
}