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