commit a49ac519c8df83c52ed67e3860c51ccad80e037a Author: yangguo@chromium.org Date: Wed Sep 17 12:50:17 2014 +0000 Serialize code stubs using stub key. Also add some tracing to the code serializer. R=mvstanton@chromium.org Review URL: https://codereview.chromium.org/556243005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24002 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 4208e62..792fda9 100644 --- node/deps/v8/src/flag-definitions.h +++ node/deps/v8/src/flag-definitions.h @@ -428,6 +428,7 @@ DEFINE_BOOL(trace_stub_failures, false, "trace deoptimization of generated code stubs") DEFINE_BOOL(serialize_toplevel, false, "enable caching of toplevel scripts") +DEFINE_BOOL(trace_code_serializer, false, "trace code serializer") // compiler.cc DEFINE_INT(min_preparse_length, 1024, diff --git a/src/serialize.cc b/src/serialize.cc index 1a19ab0..9447fc8 100644 --- node/deps/v8/src/serialize.cc +++ node/deps/v8/src/serialize.cc @@ -8,6 +8,7 @@ #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" @@ -872,7 +873,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); \ @@ -1125,6 +1126,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 @@ -1311,12 +1316,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) { +void Serializer::SerializeReferenceToPreviousObject(HeapObject* heap_object, + HowToCode how_to_code, + WhereToPoint where_to_point, + int skip) { + int space = SpaceOfObject(heap_object); + int address = address_mapper_.MappedTo(heap_object); int offset = CurrentAllocationAddress(space) - address; // Shift out the bits that are always 0. offset >>= kObjectAlignmentBits; @@ -1347,12 +1352,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 +1455,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) { @@ -1782,17 +1777,32 @@ void Serializer::InitializeCodeAddressMap() { ScriptData* CodeSerializer::Serialize(Isolate* isolate, Handle info, Handle source) { + base::ElapsedTimer timer; + if (FLAG_profile_deserialization) timer.Start(); + // Serialize code object. List payload; ListSnapshotSink list_sink(&payload); - CodeSerializer cs(isolate, &list_sink, *source); + DebugSnapshotSink debug_sink(&list_sink); + SnapshotByteSink* sink = FLAG_trace_code_serializer + ? static_cast(&debug_sink) + : static_cast(&list_sink); + CodeSerializer cs(isolate, sink, *source); DisallowHeapAllocation no_gc; Object** location = Handle::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; } @@ -1813,16 +1823,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, 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; } @@ -1832,7 +1839,11 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, SerializeBuiltin(code_object, how_to_code, where_to_point, skip); return; } - // TODO(yangguo) figure out whether other code kinds can be handled smarter. + if (code_object->IsCodeStubOrIC()) { + SerializeCodeStub(code_object, how_to_code, where_to_point, skip); + return; + } + code_object->ClearInlineCaches(); } if (heap_object == source_) { @@ -1840,6 +1851,14 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, return; } + SerializeHeapObject(heap_object, how_to_code, where_to_point, skip); +} + + +void CodeSerializer::SerializeHeapObject(HeapObject* heap_object, + HowToCode how_to_code, + WhereToPoint where_to_point, + int skip) { 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 @@ -1851,6 +1870,13 @@ void CodeSerializer::SerializeObject(Object* o, HowToCode how_to_code, 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); @@ -1870,11 +1896,62 @@ void CodeSerializer::SerializeBuiltin(Code* builtin, HowToCode how_to_code, 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::SerializeCodeStub(Code* code, HowToCode how_to_code, + WhereToPoint where_to_point, int skip) { + 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 = code->stub_key(); + + if (CodeStub::MajorKeyFromKey(stub_key) == CodeStub::NoCacheKey()) { + if (FLAG_trace_code_serializer) { + PrintF("Encoding uncacheable code stub as heap object\n"); + } + SerializeHeapObject(code, how_to_code, where_to_point, skip); + return; + } + + if (skip != 0) { + sink_->Put(kSkip, "SkipFromSerializeCodeStub"); + sink_->PutInt(skip, "SkipDistanceFromSerializeCodeStub"); + } + + 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, int skip) { @@ -1883,6 +1960,10 @@ void CodeSerializer::SerializeSourceObject(HowToCode how_to_code, sink_->PutInt(skip, "SkipDistanceFromSerializeSourceObject"); } + 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 +1975,36 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, Handle 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 attached_objects = Vector::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 <= PROPERTY_CELL_SPACE; i++) { + deserializer.set_reservation(i, scd.GetReservation(i)); + } + + // Prepare and register list of attached objects. + Vector code_stub_keys = scd.CodeStubKeys(); + Vector > attached_objects = Vector >::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 +2017,35 @@ Handle CodeSerializer::Deserialize(Isolate* isolate, SerializedCodeData::SerializedCodeData(List* payload, CodeSerializer* cs) : owns_script_data_(true) { DisallowHeapAllocation no_gc; - int data_length = payload->length() + kHeaderEntries * kIntSize; + List* 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(data_length); DCHECK(IsAligned(reinterpret_cast(data), kPointerAlignment)); - CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(), - static_cast(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++) { SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i)); } + + // Copy code stub keys. + CopyBytes(data + kHeaderSize, reinterpret_cast(stub_keys->begin()), + stub_keys_size); + + // Copy serialized data. + CopyBytes(data + kHeaderSize + stub_keys_size, payload->begin(), + static_cast(payload->length())); } diff --git a/src/serialize.h b/src/serialize.h index 066d75f..71b274b 100644 --- node/deps/v8/src/serialize.h +++ node/deps/v8/src/serialize.h @@ -257,7 +257,7 @@ class Deserializer: public SerializerDeserializer { // Serialized user code reference certain objects that are provided in a list // By calling this method, we assume that we are deserializing user code. - void SetAttachedObjects(Vector* attached_objects) { + void SetAttachedObjects(Vector >* attached_objects) { attached_objects_ = attached_objects; } @@ -308,7 +308,7 @@ class Deserializer: public SerializerDeserializer { Isolate* isolate_; // Objects from the attached object descriptions in the serialized user code. - Vector* attached_objects_; + Vector >* attached_objects_; SnapshotByteSource* source_; // This is the address of the next object that will be allocated in each @@ -459,12 +459,10 @@ class Serializer : public SerializerDeserializer { HowToCode how_to_code, WhereToPoint where_to_point, int skip) = 0; - void SerializeReferenceToPreviousObject( - int space, - int address, - HowToCode how_to_code, - WhereToPoint where_to_point, - int skip); + void SerializeReferenceToPreviousObject(HeapObject* heap_object, + HowToCode how_to_code, + WhereToPoint where_to_point, + int skip); void InitializeAllocators(); // This will return the space for an object. static int SpaceOfObject(HeapObject* object); @@ -594,20 +592,29 @@ class CodeSerializer : public Serializer { Handle source); static const int kSourceObjectIndex = 0; + static const int kCodeStubsBaseIndex = 1; String* source() { DCHECK(!AllowHeapAllocation::IsAllowed()); return source_; } + List* stub_keys() { return &stub_keys_; } + private: void SerializeBuiltin(Code* builtin, HowToCode how_to_code, WhereToPoint where_to_point, int skip); + void SerializeCodeStub(Code* code, HowToCode how_to_code, + WhereToPoint where_to_point, int skip); void SerializeSourceObject(HowToCode how_to_code, WhereToPoint where_to_point, int skip); + void SerializeHeapObject(HeapObject* heap_object, HowToCode how_to_code, + WhereToPoint where_to_point, int skip); + int AddCodeStubKey(uint32_t stub_key); DisallowHeapAllocation no_gc_; String* source_; + List stub_keys_; DISALLOW_COPY_AND_ASSIGN(CodeSerializer); }; @@ -638,12 +645,22 @@ class SerializedCodeData { return result; } + Vector CodeStubKeys() const { + return Vector( + reinterpret_cast(script_data_->data() + kHeaderSize), + GetHeaderValue(kNumCodeStubKeysOffset)); + } + const byte* Payload() const { - return script_data_->data() + kHeaderEntries * kIntSize; + int code_stubs_size = GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size; + return script_data_->data() + kHeaderSize + code_stubs_size; } int PayloadLength() const { - return script_data_->length() - kHeaderEntries * kIntSize; + int payload_length = GetHeaderValue(kPayloadLengthOffset); + DCHECK_EQ(script_data_->data() + script_data_->length(), + Payload() + payload_length); + return payload_length; } int GetReservation(int space) const { @@ -666,10 +683,21 @@ class SerializedCodeData { // The data header consists of int-sized entries: // [0] version hash - // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. + // [1] number of code stub keys + // [2] payload length + // [3..9] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE. static const int kCheckSumOffset = 0; - static const int kReservationsOffset = 1; - static const int kHeaderEntries = 8; + static const int kNumCodeStubKeysOffset = 1; + static const int kPayloadLengthOffset = 2; + static const int kReservationsOffset = 3; + + static const int kNumSpaces = PROPERTY_CELL_SPACE - NEW_SPACE + 1; + static const int kHeaderEntries = kReservationsOffset + kNumSpaces; + static const int kHeaderSize = kHeaderEntries * kIntSize; + + // Following the header, we store, in sequential order + // - code stub keys + // - serialization payload ScriptData* script_data_; bool owns_script_data_;