Commit a49ac519 authored by yangguo@chromium.org's avatar yangguo@chromium.org

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
parent cbf66711
......@@ -246,6 +246,22 @@ void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
}
void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
// Code stubs with special cache cannot be recreated from stub key.
*code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
}
MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
HandleScope scope(isolate);
Handle<Code> code;
void** value_out = reinterpret_cast<void**>(&code);
Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
return scope.CloseAndEscape(code);
}
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
// Generate the uninitialized versions of the stub.
......
......@@ -187,6 +187,8 @@ class CodeStub BASE_EMBEDDED {
static void InitializeDescriptor(Isolate* isolate, uint32_t key,
CodeStubDescriptor* desc);
static MaybeHandle<Code> GetCode(Isolate* isolate, uint32_t key);
// Returns information for computing the number key.
virtual Major MajorKey() const = 0;
uint32_t MinorKey() const { return minor_key_; }
......@@ -261,6 +263,8 @@ class CodeStub BASE_EMBEDDED {
static void Dispatch(Isolate* isolate, uint32_t key, void** value_out,
DispatchedCall call);
static void GetCodeDispatchCall(CodeStub* stub, void** value_out);
STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits));
class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {};
class MinorKeyBits: public BitField<uint32_t,
......
......@@ -438,6 +438,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,
......
......@@ -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); \
......@@ -1137,6 +1138,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
......@@ -1314,12 +1319,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;
......@@ -1350,12 +1355,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) {
......@@ -1458,12 +1458,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) {
......@@ -1787,17 +1782,32 @@ 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);
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;
}
......@@ -1818,16 +1828,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;
}
......@@ -1837,7 +1844,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_) {
......@@ -1845,6 +1856,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
......@@ -1856,6 +1875,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);
......@@ -1876,11 +1902,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) {
......@@ -1889,6 +1966,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");
......@@ -1900,22 +1981,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 <= PROPERTY_CELL_SPACE; 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();
......@@ -1928,18 +2023,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++) {
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()));
}
......
......@@ -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<Object*>* attached_objects) {
void SetAttachedObjects(Vector<Handle<Object> >* 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<Object*>* attached_objects_;
Vector<Handle<Object> >* 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<String> source);
static const int kSourceObjectIndex = 0;
static const int kCodeStubsBaseIndex = 1;
String* source() {
DCHECK(!AllowHeapAllocation::IsAllowed());
return source_;
}
List<uint32_t>* 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<uint32_t> stub_keys_;
DISALLOW_COPY_AND_ASSIGN(CodeSerializer);
};
......@@ -638,12 +645,22 @@ class SerializedCodeData {
return result;
}
Vector<const uint32_t> CodeStubKeys() const {
return Vector<const uint32_t>(
reinterpret_cast<const uint32_t*>(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_;
......
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