Home | History | Annotate | Download | only in snapshot
      1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // The common functionality when building with or without snapshots.
      6 
      7 #include "src/snapshot/snapshot.h"
      8 
      9 #include "src/api.h"
     10 #include "src/base/platform/platform.h"
     11 #include "src/full-codegen/full-codegen.h"
     12 #include "src/snapshot/deserializer.h"
     13 #include "src/snapshot/snapshot-source-sink.h"
     14 #include "src/version.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 #ifdef DEBUG
     20 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
     21   return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
     22 }
     23 #endif  // DEBUG
     24 
     25 
     26 bool Snapshot::HaveASnapshotToStartFrom(Isolate* isolate) {
     27   // Do not use snapshots if the isolate is used to create snapshots.
     28   return isolate->snapshot_blob() != NULL &&
     29          isolate->snapshot_blob()->data != NULL;
     30 }
     31 
     32 
     33 uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
     34   DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
     35   if (!isolate->snapshot_available()) {
     36     return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
     37   }
     38   uint32_t size;
     39   int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
     40   memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
     41   return size;
     42 }
     43 
     44 
     45 bool Snapshot::Initialize(Isolate* isolate) {
     46   if (!isolate->snapshot_available()) return false;
     47   base::ElapsedTimer timer;
     48   if (FLAG_profile_deserialization) timer.Start();
     49 
     50   const v8::StartupData* blob = isolate->snapshot_blob();
     51   Vector<const byte> startup_data = ExtractStartupData(blob);
     52   SnapshotData snapshot_data(startup_data);
     53   Deserializer deserializer(&snapshot_data);
     54   bool success = isolate->Init(&deserializer);
     55   if (FLAG_profile_deserialization) {
     56     double ms = timer.Elapsed().InMillisecondsF();
     57     int bytes = startup_data.length();
     58     PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
     59   }
     60   return success;
     61 }
     62 
     63 MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
     64     Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
     65     size_t context_index) {
     66   if (!isolate->snapshot_available()) return Handle<Context>();
     67   base::ElapsedTimer timer;
     68   if (FLAG_profile_deserialization) timer.Start();
     69 
     70   const v8::StartupData* blob = isolate->snapshot_blob();
     71   Vector<const byte> context_data =
     72       ExtractContextData(blob, static_cast<int>(context_index));
     73   SnapshotData snapshot_data(context_data);
     74   Deserializer deserializer(&snapshot_data);
     75 
     76   MaybeHandle<Object> maybe_context =
     77       deserializer.DeserializePartial(isolate, global_proxy);
     78   Handle<Object> result;
     79   if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
     80   CHECK(result->IsContext());
     81   if (FLAG_profile_deserialization) {
     82     double ms = timer.Elapsed().InMillisecondsF();
     83     int bytes = context_data.length();
     84     PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
     85            context_index, bytes, ms);
     86   }
     87   return Handle<Context>::cast(result);
     88 }
     89 
     90 void UpdateMaxRequirementPerPage(
     91     uint32_t* requirements,
     92     Vector<const SerializedData::Reservation> reservations) {
     93   int space = 0;
     94   uint32_t current_requirement = 0;
     95   for (const auto& reservation : reservations) {
     96     current_requirement += reservation.chunk_size();
     97     if (reservation.is_last()) {
     98       requirements[space] = std::max(requirements[space], current_requirement);
     99       current_requirement = 0;
    100       space++;
    101     }
    102   }
    103   DCHECK_EQ(i::Serializer::kNumberOfSpaces, space);
    104 }
    105 
    106 void CalculateFirstPageSizes(const SnapshotData* startup_snapshot,
    107                              const List<SnapshotData*>* context_snapshots,
    108                              uint32_t* sizes_out) {
    109   if (FLAG_profile_deserialization) {
    110     int startup_total = 0;
    111     PrintF("Deserialization will reserve:\n");
    112     for (const auto& reservation : startup_snapshot->Reservations()) {
    113       startup_total += reservation.chunk_size();
    114     }
    115     PrintF("%10d bytes per isolate\n", startup_total);
    116     for (int i = 0; i < context_snapshots->length(); i++) {
    117       int context_total = 0;
    118       for (const auto& reservation : context_snapshots->at(i)->Reservations()) {
    119         context_total += reservation.chunk_size();
    120       }
    121       PrintF("%10d bytes per context #%d\n", context_total, i);
    122     }
    123   }
    124 
    125   uint32_t startup_requirements[i::Serializer::kNumberOfSpaces];
    126   uint32_t context_requirements[i::Serializer::kNumberOfSpaces];
    127   for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    128     startup_requirements[space] = 0;
    129     context_requirements[space] = 0;
    130   }
    131 
    132   UpdateMaxRequirementPerPage(startup_requirements,
    133                               startup_snapshot->Reservations());
    134   for (const auto& context_snapshot : *context_snapshots) {
    135     UpdateMaxRequirementPerPage(context_requirements,
    136                                 context_snapshot->Reservations());
    137   }
    138 
    139   for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    140     // If the space requirement for a page is less than a page size, we consider
    141     // limiting the size of the first page in order to save memory on startup.
    142     uint32_t required = startup_requirements[space] +
    143                         2 * context_requirements[space] +
    144                         Page::kObjectStartOffset;
    145     // Add a small allowance to the code space for small scripts.
    146     if (space == CODE_SPACE) required += 32 * KB;
    147 
    148     if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
    149       uint32_t max_size =
    150           MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
    151       sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size);
    152     }
    153   }
    154 }
    155 
    156 v8::StartupData Snapshot::CreateSnapshotBlob(
    157     const SnapshotData* startup_snapshot,
    158     const List<SnapshotData*>* context_snapshots) {
    159   int num_contexts = context_snapshots->length();
    160   int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
    161   int total_length = startup_snapshot_offset;
    162   total_length += startup_snapshot->RawData().length();
    163   for (const auto& context_snapshot : *context_snapshots) {
    164     total_length += context_snapshot->RawData().length();
    165   }
    166 
    167   uint32_t first_page_sizes[kNumPagedSpaces];
    168   CalculateFirstPageSizes(startup_snapshot, context_snapshots,
    169                           first_page_sizes);
    170 
    171   char* data = new char[total_length];
    172   memcpy(data + kFirstPageSizesOffset, first_page_sizes,
    173          kNumPagedSpaces * kInt32Size);
    174   memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
    175   int payload_offset = StartupSnapshotOffset(num_contexts);
    176   int payload_length = startup_snapshot->RawData().length();
    177   memcpy(data + payload_offset, startup_snapshot->RawData().start(),
    178          payload_length);
    179   if (FLAG_profile_deserialization) {
    180     PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
    181            payload_length);
    182   }
    183   payload_offset += payload_length;
    184   for (int i = 0; i < num_contexts; i++) {
    185     memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size);
    186     SnapshotData* context_snapshot = context_snapshots->at(i);
    187     payload_length = context_snapshot->RawData().length();
    188     memcpy(data + payload_offset, context_snapshot->RawData().start(),
    189            payload_length);
    190     if (FLAG_profile_deserialization) {
    191       PrintF("%10d bytes for context #%d\n", payload_length, i);
    192     }
    193     payload_offset += payload_length;
    194   }
    195 
    196   v8::StartupData result = {data, total_length};
    197   return result;
    198 }
    199 
    200 int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
    201   CHECK_LT(kNumberOfContextsOffset, data->raw_size);
    202   int num_contexts;
    203   memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size);
    204   return num_contexts;
    205 }
    206 
    207 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
    208   int num_contexts = ExtractNumContexts(data);
    209   int startup_offset = StartupSnapshotOffset(num_contexts);
    210   CHECK_LT(startup_offset, data->raw_size);
    211   int first_context_offset;
    212   memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0),
    213          kInt32Size);
    214   CHECK_LT(first_context_offset, data->raw_size);
    215   int startup_length = first_context_offset - startup_offset;
    216   const byte* startup_data =
    217       reinterpret_cast<const byte*>(data->data + startup_offset);
    218   return Vector<const byte>(startup_data, startup_length);
    219 }
    220 
    221 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
    222                                                 int index) {
    223   int num_contexts = ExtractNumContexts(data);
    224   CHECK_LT(index, num_contexts);
    225 
    226   int context_offset;
    227   memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index),
    228          kInt32Size);
    229   int next_context_offset;
    230   if (index == num_contexts - 1) {
    231     next_context_offset = data->raw_size;
    232   } else {
    233     memcpy(&next_context_offset,
    234            data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size);
    235     CHECK_LT(next_context_offset, data->raw_size);
    236   }
    237 
    238   const byte* context_data =
    239       reinterpret_cast<const byte*>(data->data + context_offset);
    240   int context_length = next_context_offset - context_offset;
    241   return Vector<const byte>(context_data, context_length);
    242 }
    243 
    244 SnapshotData::SnapshotData(const Serializer* serializer) {
    245   DisallowHeapAllocation no_gc;
    246   List<Reservation> reservations;
    247   serializer->EncodeReservations(&reservations);
    248   const List<byte>* payload = serializer->sink()->data();
    249 
    250   // Calculate sizes.
    251   int reservation_size = reservations.length() * kInt32Size;
    252   int size = kHeaderSize + reservation_size + payload->length();
    253 
    254   // Allocate backing store and create result data.
    255   AllocateData(size);
    256 
    257   // Set header values.
    258   SetMagicNumber(serializer->isolate());
    259   SetHeaderValue(kCheckSumOffset, Version::Hash());
    260   SetHeaderValue(kNumReservationsOffset, reservations.length());
    261   SetHeaderValue(kPayloadLengthOffset, payload->length());
    262 
    263   // Copy reservation chunk sizes.
    264   CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
    265             reservation_size);
    266 
    267   // Copy serialized data.
    268   CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(),
    269             static_cast<size_t>(payload->length()));
    270 }
    271 
    272 bool SnapshotData::IsSane() {
    273   return GetHeaderValue(kCheckSumOffset) == Version::Hash();
    274 }
    275 
    276 Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
    277   return Vector<const Reservation>(
    278       reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
    279       GetHeaderValue(kNumReservationsOffset));
    280 }
    281 
    282 Vector<const byte> SnapshotData::Payload() const {
    283   int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
    284   const byte* payload = data_ + kHeaderSize + reservations_size;
    285   int length = GetHeaderValue(kPayloadLengthOffset);
    286   DCHECK_EQ(data_ + size_, payload + length);
    287   return Vector<const byte>(payload, length);
    288 }
    289 
    290 }  // namespace internal
    291 }  // namespace v8
    292