| Index: src/snapshot/snapshot-common.cc
|
| diff --git a/src/snapshot/snapshot-common.cc b/src/snapshot/snapshot-common.cc
|
| index 655563ccd9cafbf7aaf3d43aa5a91601376cec56..f63ed3452df705c50445eb5a80778cc14dbe4158 100644
|
| --- a/src/snapshot/snapshot-common.cc
|
| +++ b/src/snapshot/snapshot-common.cc
|
| @@ -18,8 +18,7 @@ namespace internal {
|
|
|
| #ifdef DEBUG
|
| bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
|
| - return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
|
| - !Snapshot::ExtractContextData(snapshot_blob).is_empty();
|
| + return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
|
| }
|
| #endif // DEBUG
|
|
|
| @@ -61,15 +60,14 @@ bool Snapshot::Initialize(Isolate* isolate) {
|
| return success;
|
| }
|
|
|
| -
|
| MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
|
| - Isolate* isolate, Handle<JSGlobalProxy> global_proxy) {
|
| + Isolate* isolate, Handle<JSGlobalProxy> global_proxy, int context_index) {
|
| if (!isolate->snapshot_available()) return Handle<Context>();
|
| base::ElapsedTimer timer;
|
| if (FLAG_profile_deserialization) timer.Start();
|
|
|
| const v8::StartupData* blob = isolate->snapshot_blob();
|
| - Vector<const byte> context_data = ExtractContextData(blob);
|
| + Vector<const byte> context_data = ExtractContextData(blob, context_index);
|
| SnapshotData snapshot_data(context_data);
|
| Deserializer deserializer(&snapshot_data);
|
|
|
| @@ -81,133 +79,164 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
|
| if (FLAG_profile_deserialization) {
|
| double ms = timer.Elapsed().InMillisecondsF();
|
| int bytes = context_data.length();
|
| - PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms);
|
| + PrintF("[Deserializing context #%d (%d bytes) took %0.3f ms]\n",
|
| + context_index, bytes, ms);
|
| }
|
| return Handle<Context>::cast(result);
|
| }
|
|
|
| +void UpdateMaxRequirementPerPage(
|
| + uint32_t* requirements,
|
| + Vector<const SerializedData::Reservation> reservations) {
|
| + int space = 0;
|
| + uint32_t current_requirement = 0;
|
| + for (const auto& reservation : reservations) {
|
| + current_requirement += reservation.chunk_size();
|
| + if (reservation.is_last()) {
|
| + requirements[space] = std::max(requirements[space], current_requirement);
|
| + current_requirement = 0;
|
| + space++;
|
| + }
|
| + }
|
| + DCHECK_EQ(i::Serializer::kNumberOfSpaces, space);
|
| +}
|
| +
|
| void CalculateFirstPageSizes(const SnapshotData* startup_snapshot,
|
| - const SnapshotData* context_snapshot,
|
| + const List<SnapshotData*>* context_snapshots,
|
| uint32_t* sizes_out) {
|
| - Vector<const SerializedData::Reservation> startup_reservations =
|
| - startup_snapshot->Reservations();
|
| - Vector<const SerializedData::Reservation> context_reservations =
|
| - context_snapshot->Reservations();
|
| - int startup_index = 0;
|
| - int context_index = 0;
|
| -
|
| if (FLAG_profile_deserialization) {
|
| int startup_total = 0;
|
| - int context_total = 0;
|
| - for (const auto& reservation : startup_reservations) {
|
| + PrintF("Deserialization will reserve:\n");
|
| + for (const auto& reservation : startup_snapshot->Reservations()) {
|
| startup_total += reservation.chunk_size();
|
| }
|
| - for (const auto& reservation : context_reservations) {
|
| - context_total += reservation.chunk_size();
|
| + PrintF("%10d bytes per isolate\n", startup_total);
|
| + for (int i = 0; i < context_snapshots->length(); i++) {
|
| + int context_total = 0;
|
| + for (const auto& reservation : context_snapshots->at(i)->Reservations()) {
|
| + context_total += reservation.chunk_size();
|
| + }
|
| + PrintF("%10d bytes per context #%d\n", context_total, i);
|
| }
|
| - PrintF(
|
| - "Deserialization will reserve:\n"
|
| - "%10d bytes per isolate\n"
|
| - "%10d bytes per context\n",
|
| - startup_total, context_total);
|
| }
|
|
|
| + uint32_t startup_requirements[i::Serializer::kNumberOfSpaces];
|
| + uint32_t context_requirements[i::Serializer::kNumberOfSpaces];
|
| for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
|
| - bool single_chunk = true;
|
| - while (!startup_reservations[startup_index].is_last()) {
|
| - single_chunk = false;
|
| - startup_index++;
|
| - }
|
| - while (!context_reservations[context_index].is_last()) {
|
| - single_chunk = false;
|
| - context_index++;
|
| - }
|
| + startup_requirements[space] = 0;
|
| + context_requirements[space] = 0;
|
| + }
|
|
|
| - uint32_t required = kMaxUInt32;
|
| - if (single_chunk) {
|
| - // If both the startup snapshot data and the context snapshot data on
|
| - // this space fit in a single page, then we consider limiting the size
|
| - // of the first page. For this, we add the chunk sizes and some extra
|
| - // allowance. This way we achieve a smaller startup memory footprint.
|
| - required = (startup_reservations[startup_index].chunk_size() +
|
| - 2 * context_reservations[context_index].chunk_size()) +
|
| - Page::kObjectStartOffset;
|
| - // Add a small allowance to the code space for small scripts.
|
| - if (space == CODE_SPACE) required += 32 * KB;
|
| - }
|
| + UpdateMaxRequirementPerPage(startup_requirements,
|
| + startup_snapshot->Reservations());
|
| + for (const auto& context_snapshot : *context_snapshots) {
|
| + UpdateMaxRequirementPerPage(context_requirements,
|
| + context_snapshot->Reservations());
|
| + }
|
| +
|
| + for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
|
| + // If the space requirement for a page is less than a page size, we consider
|
| + // limiting the size of the first page in order to save memory on startup.
|
| + uint32_t required = startup_requirements[space] +
|
| + 2 * context_requirements[space] +
|
| + Page::kObjectStartOffset;
|
| + // Add a small allowance to the code space for small scripts.
|
| + if (space == CODE_SPACE) required += 32 * KB;
|
|
|
| if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
|
| uint32_t max_size =
|
| MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
|
| - sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size);
|
| - } else {
|
| - DCHECK(single_chunk);
|
| + sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size);
|
| }
|
| - startup_index++;
|
| - context_index++;
|
| }
|
| -
|
| - DCHECK_EQ(startup_reservations.length(), startup_index);
|
| - DCHECK_EQ(context_reservations.length(), context_index);
|
| }
|
|
|
| v8::StartupData Snapshot::CreateSnapshotBlob(
|
| - const StartupSerializer* startup_serializer,
|
| - const PartialSerializer* context_serializer) {
|
| - SnapshotData startup_snapshot(startup_serializer);
|
| - SnapshotData context_snapshot(context_serializer);
|
| - Vector<const byte> startup_data = startup_snapshot.RawData();
|
| - Vector<const byte> context_data = context_snapshot.RawData();
|
| + const SnapshotData* startup_snapshot,
|
| + const List<SnapshotData*>* context_snapshots) {
|
| + int num_contexts = context_snapshots->length();
|
| + int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
|
| + int total_length = startup_snapshot_offset;
|
| + total_length += startup_snapshot->RawData().length();
|
| + for (const auto& context_snapshot : *context_snapshots) {
|
| + total_length += context_snapshot->RawData().length();
|
| + }
|
|
|
| uint32_t first_page_sizes[kNumPagedSpaces];
|
| -
|
| - CalculateFirstPageSizes(&startup_snapshot, &context_snapshot,
|
| + CalculateFirstPageSizes(startup_snapshot, context_snapshots,
|
| first_page_sizes);
|
|
|
| - int startup_length = startup_data.length();
|
| - int context_length = context_data.length();
|
| - int context_offset = ContextOffset(startup_length);
|
| -
|
| - int length = context_offset + context_length;
|
| - char* data = new char[length];
|
| -
|
| + char* data = new char[total_length];
|
| memcpy(data + kFirstPageSizesOffset, first_page_sizes,
|
| kNumPagedSpaces * kInt32Size);
|
| - memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size);
|
| - memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
|
| - memcpy(data + context_offset, context_data.begin(), context_length);
|
| - v8::StartupData result = {data, length};
|
| -
|
| + memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
|
| + int payload_offset = StartupSnapshotOffset(num_contexts);
|
| + int payload_length = startup_snapshot->RawData().length();
|
| + memcpy(data + payload_offset, startup_snapshot->RawData().start(),
|
| + payload_length);
|
| if (FLAG_profile_deserialization) {
|
| - PrintF(
|
| - "Snapshot blob consists of:\n"
|
| - "%10d bytes for startup\n"
|
| - "%10d bytes for context\n",
|
| - startup_length, context_length);
|
| + PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
|
| + payload_length);
|
| }
|
| + payload_offset += payload_length;
|
| + for (int i = 0; i < num_contexts; i++) {
|
| + memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size);
|
| + SnapshotData* context_snapshot = context_snapshots->at(i);
|
| + payload_length = context_snapshot->RawData().length();
|
| + memcpy(data + payload_offset, context_snapshot->RawData().start(),
|
| + payload_length);
|
| + if (FLAG_profile_deserialization) {
|
| + PrintF("%10d bytes for context #%d\n", payload_length, i);
|
| + }
|
| + payload_offset += payload_length;
|
| + }
|
| +
|
| + v8::StartupData result = {data, total_length};
|
| return result;
|
| }
|
|
|
| +int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
|
| + CHECK_LT(kNumberOfContextsOffset, data->raw_size);
|
| + int num_contexts;
|
| + memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size);
|
| + return num_contexts;
|
| +}
|
| +
|
| Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
|
| - DCHECK_LT(kIntSize, data->raw_size);
|
| - int startup_length;
|
| - memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size);
|
| - DCHECK_LT(startup_length, data->raw_size);
|
| + int num_contexts = ExtractNumContexts(data);
|
| + int startup_offset = StartupSnapshotOffset(num_contexts);
|
| + CHECK_LT(startup_offset, data->raw_size);
|
| + int first_context_offset;
|
| + memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0),
|
| + kInt32Size);
|
| + CHECK_LT(first_context_offset, data->raw_size);
|
| + int startup_length = first_context_offset - startup_offset;
|
| const byte* startup_data =
|
| - reinterpret_cast<const byte*>(data->data + kStartupDataOffset);
|
| + reinterpret_cast<const byte*>(data->data + startup_offset);
|
| return Vector<const byte>(startup_data, startup_length);
|
| }
|
|
|
| +Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
|
| + int index) {
|
| + CHECK_LE(0, index);
|
| + int num_contexts = ExtractNumContexts(data);
|
| + CHECK_LT(index, num_contexts);
|
| +
|
| + int context_offset;
|
| + memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index),
|
| + kInt32Size);
|
| + int next_context_offset;
|
| + if (index == num_contexts - 1) {
|
| + next_context_offset = data->raw_size;
|
| + } else {
|
| + memcpy(&next_context_offset,
|
| + data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size);
|
| + CHECK_LT(next_context_offset, data->raw_size);
|
| + }
|
|
|
| -Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
|
| - DCHECK_LT(kIntSize, data->raw_size);
|
| - int startup_length;
|
| - memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize);
|
| - int context_offset = ContextOffset(startup_length);
|
| const byte* context_data =
|
| reinterpret_cast<const byte*>(data->data + context_offset);
|
| - DCHECK_LT(context_offset, data->raw_size);
|
| - int context_length = data->raw_size - context_offset;
|
| + int context_length = next_context_offset - context_offset;
|
| return Vector<const byte>(context_data, context_length);
|
| }
|
|
|
|
|