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 bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) {
     26   // Do not use snapshots if the isolate is used to create snapshots.
     27   const v8::StartupData* blob = isolate->snapshot_blob();
     28   if (blob == nullptr) return false;
     29   if (blob->data == nullptr) return false;
     30   size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob));
     31   return index < num_contexts;
     32 }
     33 
     34 bool Snapshot::Initialize(Isolate* isolate) {
     35   if (!isolate->snapshot_available()) return false;
     36   base::ElapsedTimer timer;
     37   if (FLAG_profile_deserialization) timer.Start();
     38 
     39   const v8::StartupData* blob = isolate->snapshot_blob();
     40   Vector<const byte> startup_data = ExtractStartupData(blob);
     41   SnapshotData snapshot_data(startup_data);
     42   Deserializer deserializer(&snapshot_data);
     43   bool success = isolate->Init(&deserializer);
     44   if (FLAG_profile_deserialization) {
     45     double ms = timer.Elapsed().InMillisecondsF();
     46     int bytes = startup_data.length();
     47     PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
     48   }
     49   return success;
     50 }
     51 
     52 MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
     53     Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
     54     size_t context_index) {
     55   if (!isolate->snapshot_available()) return Handle<Context>();
     56   base::ElapsedTimer timer;
     57   if (FLAG_profile_deserialization) timer.Start();
     58 
     59   const v8::StartupData* blob = isolate->snapshot_blob();
     60   Vector<const byte> context_data =
     61       ExtractContextData(blob, static_cast<int>(context_index));
     62   SnapshotData snapshot_data(context_data);
     63   Deserializer deserializer(&snapshot_data);
     64 
     65   MaybeHandle<Object> maybe_context =
     66       deserializer.DeserializePartial(isolate, global_proxy);
     67   Handle<Object> result;
     68   if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
     69   CHECK(result->IsContext());
     70   if (FLAG_profile_deserialization) {
     71     double ms = timer.Elapsed().InMillisecondsF();
     72     int bytes = context_data.length();
     73     PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
     74            context_index, bytes, ms);
     75   }
     76   return Handle<Context>::cast(result);
     77 }
     78 
     79 void ProfileDeserialization(const SnapshotData* startup_snapshot,
     80                             const List<SnapshotData*>* context_snapshots) {
     81   if (FLAG_profile_deserialization) {
     82     int startup_total = 0;
     83     PrintF("Deserialization will reserve:\n");
     84     for (const auto& reservation : startup_snapshot->Reservations()) {
     85       startup_total += reservation.chunk_size();
     86     }
     87     PrintF("%10d bytes per isolate\n", startup_total);
     88     for (int i = 0; i < context_snapshots->length(); i++) {
     89       int context_total = 0;
     90       for (const auto& reservation : context_snapshots->at(i)->Reservations()) {
     91         context_total += reservation.chunk_size();
     92       }
     93       PrintF("%10d bytes per context #%d\n", context_total, i);
     94     }
     95   }
     96 }
     97 
     98 v8::StartupData Snapshot::CreateSnapshotBlob(
     99     const SnapshotData* startup_snapshot,
    100     const List<SnapshotData*>* context_snapshots) {
    101   int num_contexts = context_snapshots->length();
    102   int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
    103   int total_length = startup_snapshot_offset;
    104   total_length += startup_snapshot->RawData().length();
    105   for (const auto& context_snapshot : *context_snapshots) {
    106     total_length += context_snapshot->RawData().length();
    107   }
    108 
    109   ProfileDeserialization(startup_snapshot, context_snapshots);
    110 
    111   char* data = new char[total_length];
    112   memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
    113   int payload_offset = StartupSnapshotOffset(num_contexts);
    114   int payload_length = startup_snapshot->RawData().length();
    115   memcpy(data + payload_offset, startup_snapshot->RawData().start(),
    116          payload_length);
    117   if (FLAG_profile_deserialization) {
    118     PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
    119            payload_length);
    120   }
    121   payload_offset += payload_length;
    122   for (int i = 0; i < num_contexts; i++) {
    123     memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size);
    124     SnapshotData* context_snapshot = context_snapshots->at(i);
    125     payload_length = context_snapshot->RawData().length();
    126     memcpy(data + payload_offset, context_snapshot->RawData().start(),
    127            payload_length);
    128     if (FLAG_profile_deserialization) {
    129       PrintF("%10d bytes for context #%d\n", payload_length, i);
    130     }
    131     payload_offset += payload_length;
    132   }
    133 
    134   v8::StartupData result = {data, total_length};
    135   return result;
    136 }
    137 
    138 int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
    139   CHECK_LT(kNumberOfContextsOffset, data->raw_size);
    140   int num_contexts;
    141   memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size);
    142   return num_contexts;
    143 }
    144 
    145 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
    146   int num_contexts = ExtractNumContexts(data);
    147   int startup_offset = StartupSnapshotOffset(num_contexts);
    148   CHECK_LT(startup_offset, data->raw_size);
    149   int first_context_offset;
    150   memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0),
    151          kInt32Size);
    152   CHECK_LT(first_context_offset, data->raw_size);
    153   int startup_length = first_context_offset - startup_offset;
    154   const byte* startup_data =
    155       reinterpret_cast<const byte*>(data->data + startup_offset);
    156   return Vector<const byte>(startup_data, startup_length);
    157 }
    158 
    159 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
    160                                                 int index) {
    161   int num_contexts = ExtractNumContexts(data);
    162   CHECK_LT(index, num_contexts);
    163 
    164   int context_offset;
    165   memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index),
    166          kInt32Size);
    167   int next_context_offset;
    168   if (index == num_contexts - 1) {
    169     next_context_offset = data->raw_size;
    170   } else {
    171     memcpy(&next_context_offset,
    172            data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size);
    173     CHECK_LT(next_context_offset, data->raw_size);
    174   }
    175 
    176   const byte* context_data =
    177       reinterpret_cast<const byte*>(data->data + context_offset);
    178   int context_length = next_context_offset - context_offset;
    179   return Vector<const byte>(context_data, context_length);
    180 }
    181 
    182 SnapshotData::SnapshotData(const Serializer* serializer) {
    183   DisallowHeapAllocation no_gc;
    184   List<Reservation> reservations;
    185   serializer->EncodeReservations(&reservations);
    186   const List<byte>* payload = serializer->sink()->data();
    187 
    188   // Calculate sizes.
    189   int reservation_size = reservations.length() * kInt32Size;
    190   int size = kHeaderSize + reservation_size + payload->length();
    191 
    192   // Allocate backing store and create result data.
    193   AllocateData(size);
    194 
    195   // Set header values.
    196   SetMagicNumber(serializer->isolate());
    197   SetHeaderValue(kCheckSumOffset, Version::Hash());
    198   SetHeaderValue(kNumReservationsOffset, reservations.length());
    199   SetHeaderValue(kPayloadLengthOffset, payload->length());
    200 
    201   // Copy reservation chunk sizes.
    202   CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
    203             reservation_size);
    204 
    205   // Copy serialized data.
    206   CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(),
    207             static_cast<size_t>(payload->length()));
    208 }
    209 
    210 bool SnapshotData::IsSane() {
    211   return GetHeaderValue(kCheckSumOffset) == Version::Hash();
    212 }
    213 
    214 Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
    215   return Vector<const Reservation>(
    216       reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
    217       GetHeaderValue(kNumReservationsOffset));
    218 }
    219 
    220 Vector<const byte> SnapshotData::Payload() const {
    221   int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
    222   const byte* payload = data_ + kHeaderSize + reservations_size;
    223   int length = GetHeaderValue(kPayloadLengthOffset);
    224   DCHECK_EQ(data_ + size_, payload + length);
    225   return Vector<const byte>(payload, length);
    226 }
    227 
    228 }  // namespace internal
    229 }  // namespace v8
    230