LCOV - code coverage report
Current view: top level - src/snapshot - snapshot-common.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 139 142 97.9 %
Date: 2019-04-17 Functions: 17 18 94.4 %

          Line data    Source code
       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/base/platform/platform.h"
      10             : #include "src/counters.h"
      11             : #include "src/snapshot/partial-deserializer.h"
      12             : #include "src/snapshot/read-only-deserializer.h"
      13             : #include "src/snapshot/startup-deserializer.h"
      14             : #include "src/version.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : #ifdef DEBUG
      20             : bool Snapshot::SnapshotIsValid(const v8::StartupData* snapshot_blob) {
      21             :   return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
      22             : }
      23             : #endif  // DEBUG
      24             : 
      25          45 : 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          45 :   if (blob == nullptr) return false;
      29          45 :   if (blob->data == nullptr) return false;
      30          45 :   size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob));
      31          45 :   return index < num_contexts;
      32             : }
      33             : 
      34       62314 : bool Snapshot::Initialize(Isolate* isolate) {
      35       62314 :   if (!isolate->snapshot_available()) return false;
      36             :   RuntimeCallTimerScope rcs_timer(isolate,
      37       62315 :                                   RuntimeCallCounterId::kDeserializeIsolate);
      38             :   base::ElapsedTimer timer;
      39       62314 :   if (FLAG_profile_deserialization) timer.Start();
      40             : 
      41             :   const v8::StartupData* blob = isolate->snapshot_blob();
      42       62314 :   CheckVersion(blob);
      43       62313 :   CHECK(VerifyChecksum(blob));
      44       62309 :   Vector<const byte> startup_data = ExtractStartupData(blob);
      45             :   SnapshotData startup_snapshot_data(startup_data);
      46             :   Vector<const byte> read_only_data = ExtractReadOnlyData(blob);
      47             :   SnapshotData read_only_snapshot_data(read_only_data);
      48             :   StartupDeserializer startup_deserializer(&startup_snapshot_data);
      49             :   ReadOnlyDeserializer read_only_deserializer(&read_only_snapshot_data);
      50       62315 :   startup_deserializer.SetRehashability(ExtractRehashability(blob));
      51       62313 :   read_only_deserializer.SetRehashability(ExtractRehashability(blob));
      52             :   bool success =
      53       62313 :       isolate->InitWithSnapshot(&read_only_deserializer, &startup_deserializer);
      54       62315 :   if (FLAG_profile_deserialization) {
      55           5 :     double ms = timer.Elapsed().InMillisecondsF();
      56             :     int bytes = startup_data.length();
      57           5 :     PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
      58             :   }
      59             :   return success;
      60             : }
      61             : 
      62       91693 : MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
      63             :     Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index,
      64             :     v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
      65       91693 :   if (!isolate->snapshot_available()) return Handle<Context>();
      66             :   RuntimeCallTimerScope rcs_timer(isolate,
      67       91648 :                                   RuntimeCallCounterId::kDeserializeContext);
      68             :   base::ElapsedTimer timer;
      69       91648 :   if (FLAG_profile_deserialization) timer.Start();
      70             : 
      71             :   const v8::StartupData* blob = isolate->snapshot_blob();
      72       91648 :   bool can_rehash = ExtractRehashability(blob);
      73             :   Vector<const byte> context_data =
      74       91648 :       ExtractContextData(blob, static_cast<uint32_t>(context_index));
      75             :   SnapshotData snapshot_data(context_data);
      76             : 
      77             :   MaybeHandle<Context> maybe_result = PartialDeserializer::DeserializeContext(
      78             :       isolate, &snapshot_data, can_rehash, global_proxy,
      79       91648 :       embedder_fields_deserializer);
      80             : 
      81             :   Handle<Context> result;
      82       91648 :   if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>();
      83             : 
      84       91648 :   if (FLAG_profile_deserialization) {
      85           5 :     double ms = timer.Elapsed().InMillisecondsF();
      86             :     int bytes = context_data.length();
      87             :     PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
      88           5 :            context_index, bytes, ms);
      89             :   }
      90       91648 :   return result;
      91             : }
      92             : 
      93         196 : void ProfileDeserialization(
      94             :     const SnapshotData* read_only_snapshot,
      95             :     const SnapshotData* startup_snapshot,
      96             :     const std::vector<SnapshotData*>& context_snapshots) {
      97         196 :   if (FLAG_profile_deserialization) {
      98             :     int startup_total = 0;
      99           5 :     PrintF("Deserialization will reserve:\n");
     100          40 :     for (const auto& reservation : read_only_snapshot->Reservations()) {
     101          30 :       startup_total += reservation.chunk_size();
     102             :     }
     103          40 :     for (const auto& reservation : startup_snapshot->Reservations()) {
     104          30 :       startup_total += reservation.chunk_size();
     105             :     }
     106           5 :     PrintF("%10d bytes per isolate\n", startup_total);
     107          15 :     for (size_t i = 0; i < context_snapshots.size(); i++) {
     108             :       int context_total = 0;
     109         165 :       for (const auto& reservation : context_snapshots[i]->Reservations()) {
     110         155 :         context_total += reservation.chunk_size();
     111             :       }
     112           5 :       PrintF("%10d bytes per context #%zu\n", context_total, i);
     113             :     }
     114             :   }
     115         196 : }
     116             : 
     117         196 : v8::StartupData Snapshot::CreateSnapshotBlob(
     118             :     const SnapshotData* startup_snapshot,
     119             :     const SnapshotData* read_only_snapshot,
     120             :     const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) {
     121         196 :   uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
     122         196 :   uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
     123             :   uint32_t total_length = startup_snapshot_offset;
     124             :   DCHECK(IsAligned(total_length, kPointerAlignment));
     125         196 :   total_length += static_cast<uint32_t>(startup_snapshot->RawData().length());
     126             :   DCHECK(IsAligned(total_length, kPointerAlignment));
     127         196 :   total_length += static_cast<uint32_t>(read_only_snapshot->RawData().length());
     128             :   DCHECK(IsAligned(total_length, kPointerAlignment));
     129         427 :   for (const auto context_snapshot : context_snapshots) {
     130         231 :     total_length += static_cast<uint32_t>(context_snapshot->RawData().length());
     131             :     DCHECK(IsAligned(total_length, kPointerAlignment));
     132             :   }
     133             : 
     134             :   ProfileDeserialization(read_only_snapshot, startup_snapshot,
     135         196 :                          context_snapshots);
     136             : 
     137         196 :   char* data = new char[total_length];
     138             :   // Zero out pre-payload data. Part of that is only used for padding.
     139         196 :   memset(data, 0, StartupSnapshotOffset(num_contexts));
     140             : 
     141             :   SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
     142         196 :   SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
     143             : 
     144             :   // Write version string into snapshot data.
     145         196 :   memset(data + kVersionStringOffset, 0, kVersionStringLength);
     146         196 :   Version::GetString(
     147         196 :       Vector<char>(data + kVersionStringOffset, kVersionStringLength));
     148             : 
     149             :   // Startup snapshot (isolate-specific data).
     150             :   uint32_t payload_offset = startup_snapshot_offset;
     151             :   uint32_t payload_length =
     152             :       static_cast<uint32_t>(startup_snapshot->RawData().length());
     153         196 :   CopyBytes(data + payload_offset,
     154             :             reinterpret_cast<const char*>(startup_snapshot->RawData().start()),
     155             :             payload_length);
     156         196 :   if (FLAG_profile_deserialization) {
     157           5 :     PrintF("Snapshot blob consists of:\n%10d bytes in %d chunks for startup\n",
     158             :            payload_length,
     159          15 :            static_cast<uint32_t>(startup_snapshot->Reservations().size()));
     160             :   }
     161         196 :   payload_offset += payload_length;
     162             : 
     163             :   // Read-only.
     164             :   SetHeaderValue(data, kReadOnlyOffsetOffset, payload_offset);
     165             :   payload_length = read_only_snapshot->RawData().length();
     166         196 :   CopyBytes(
     167             :       data + payload_offset,
     168             :       reinterpret_cast<const char*>(read_only_snapshot->RawData().start()),
     169             :       payload_length);
     170         196 :   if (FLAG_profile_deserialization) {
     171           5 :     PrintF("%10d bytes for read-only\n", payload_length);
     172             :   }
     173         196 :   payload_offset += payload_length;
     174             : 
     175             :   // Partial snapshots (context-specific data).
     176         658 :   for (uint32_t i = 0; i < num_contexts; i++) {
     177         231 :     SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
     178         462 :     SnapshotData* context_snapshot = context_snapshots[i];
     179             :     payload_length = context_snapshot->RawData().length();
     180         231 :     CopyBytes(
     181             :         data + payload_offset,
     182             :         reinterpret_cast<const char*>(context_snapshot->RawData().start()),
     183             :         payload_length);
     184         231 :     if (FLAG_profile_deserialization) {
     185           5 :       PrintF("%10d bytes in %d chunks for context #%d\n", payload_length,
     186          15 :              static_cast<uint32_t>(context_snapshot->Reservations().size()), i);
     187             :     }
     188         231 :     payload_offset += payload_length;
     189             :   }
     190             : 
     191             :   DCHECK_EQ(total_length, payload_offset);
     192         196 :   v8::StartupData result = {data, static_cast<int>(total_length)};
     193             : 
     194             :   Checksum checksum(ChecksummedContent(&result));
     195             :   SetHeaderValue(data, kChecksumPartAOffset, checksum.a());
     196             :   SetHeaderValue(data, kChecksumPartBOffset, checksum.b());
     197             : 
     198         196 :   return result;
     199             : }
     200             : 
     201      154001 : uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
     202      308002 :   CHECK_LT(kNumberOfContextsOffset, data->raw_size);
     203             :   uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
     204      154001 :   return num_contexts;
     205             : }
     206             : 
     207       62322 : bool Snapshot::VerifyChecksum(const v8::StartupData* data) {
     208             :   base::ElapsedTimer timer;
     209       62322 :   if (FLAG_profile_deserialization) timer.Start();
     210             :   uint32_t expected_a = GetHeaderValue(data, kChecksumPartAOffset);
     211             :   uint32_t expected_b = GetHeaderValue(data, kChecksumPartBOffset);
     212             :   Checksum checksum(ChecksummedContent(data));
     213       62322 :   if (FLAG_profile_deserialization) {
     214           5 :     double ms = timer.Elapsed().InMillisecondsF();
     215           5 :     PrintF("[Verifying snapshot checksum took %0.3f ms]\n", ms);
     216             :   }
     217       62321 :   return checksum.Check(expected_a, expected_b);
     218             : }
     219             : 
     220       91678 : uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data,
     221             :                                         uint32_t index) {
     222             :   // Extract the offset of the context at a given index from the StartupData,
     223             :   // and check that it is within bounds.
     224             :   uint32_t context_offset =
     225       91678 :       GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
     226       91678 :   CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
     227       91678 :   return context_offset;
     228             : }
     229             : 
     230      216274 : bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
     231      216274 :   CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size));
     232      216274 :   return GetHeaderValue(data, kRehashabilityOffset) != 0;
     233             : }
     234             : 
     235             : namespace {
     236      124609 : Vector<const byte> ExtractData(const v8::StartupData* snapshot,
     237             :                                uint32_t start_offset, uint32_t end_offset) {
     238      124609 :   CHECK_LT(start_offset, end_offset);
     239      249218 :   CHECK_LT(end_offset, snapshot->raw_size);
     240      124609 :   uint32_t length = end_offset - start_offset;
     241             :   const byte* data =
     242      124609 :       reinterpret_cast<const byte*>(snapshot->data + start_offset);
     243      124609 :   return Vector<const byte>(data, length);
     244             : }
     245             : }  // namespace
     246             : 
     247       62308 : Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
     248             :   DCHECK(SnapshotIsValid(data));
     249             : 
     250       62308 :   uint32_t num_contexts = ExtractNumContexts(data);
     251             :   return ExtractData(data, StartupSnapshotOffset(num_contexts),
     252      124614 :                      GetHeaderValue(data, kReadOnlyOffsetOffset));
     253             : }
     254             : 
     255           0 : Vector<const byte> Snapshot::ExtractReadOnlyData(const v8::StartupData* data) {
     256             :   DCHECK(SnapshotIsValid(data));
     257             : 
     258             :   return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
     259       62304 :                      GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
     260             : }
     261             : 
     262       91648 : Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
     263             :                                                 uint32_t index) {
     264       91648 :   uint32_t num_contexts = ExtractNumContexts(data);
     265       91648 :   CHECK_LT(index, num_contexts);
     266             : 
     267       91648 :   uint32_t context_offset = ExtractContextOffset(data, index);
     268             :   uint32_t next_context_offset;
     269       91648 :   if (index == num_contexts - 1) {
     270       91618 :     next_context_offset = data->raw_size;
     271             :   } else {
     272          30 :     next_context_offset = ExtractContextOffset(data, index + 1);
     273          60 :     CHECK_LT(next_context_offset, data->raw_size);
     274             :   }
     275             : 
     276             :   const byte* context_data =
     277       91648 :       reinterpret_cast<const byte*>(data->data + context_offset);
     278       91648 :   uint32_t context_length = next_context_offset - context_offset;
     279       91648 :   return Vector<const byte>(context_data, context_length);
     280             : }
     281             : 
     282       62315 : void Snapshot::CheckVersion(const v8::StartupData* data) {
     283             :   char version[kVersionStringLength];
     284             :   memset(version, 0, kVersionStringLength);
     285       62315 :   CHECK_LT(kVersionStringOffset + kVersionStringLength,
     286             :            static_cast<uint32_t>(data->raw_size));
     287       62315 :   Version::GetString(Vector<char>(version, kVersionStringLength));
     288       62313 :   if (strncmp(version, data->data + kVersionStringOffset,
     289             :               kVersionStringLength) != 0) {
     290           0 :     FATAL(
     291             :         "Version mismatch between V8 binary and snapshot.\n"
     292             :         "#   V8 binary version: %.*s\n"
     293             :         "#    Snapshot version: %.*s\n"
     294             :         "# The snapshot consists of %d bytes and contains %d context(s).",
     295             :         kVersionStringLength, version, kVersionStringLength,
     296             :         data->data + kVersionStringOffset, data->raw_size,
     297           0 :         ExtractNumContexts(data));
     298             :   }
     299       62313 : }
     300             : 
     301        1526 : SnapshotData::SnapshotData(const Serializer* serializer) {
     302             :   DisallowHeapAllocation no_gc;
     303             :   std::vector<Reservation> reservations = serializer->EncodeReservations();
     304             :   const std::vector<byte>* payload = serializer->Payload();
     305             : 
     306             :   // Calculate sizes.
     307             :   uint32_t reservation_size =
     308         763 :       static_cast<uint32_t>(reservations.size()) * kUInt32Size;
     309             :   uint32_t payload_offset = kHeaderSize + reservation_size;
     310         763 :   uint32_t padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
     311             :   uint32_t size =
     312         763 :       padded_payload_offset + static_cast<uint32_t>(payload->size());
     313             :   DCHECK(IsAligned(size, kPointerAlignment));
     314             : 
     315             :   // Allocate backing store and create result data.
     316         763 :   AllocateData(size);
     317             : 
     318             :   // Zero out pre-payload data. Part of that is only used for padding.
     319         763 :   memset(data_, 0, padded_payload_offset);
     320             : 
     321             :   // Set header values.
     322             :   SetMagicNumber();
     323         763 :   SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
     324         763 :   SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
     325             : 
     326             :   // Copy reservation chunk sizes.
     327         763 :   CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
     328             :             reservation_size);
     329             : 
     330             :   // Copy serialized data.
     331         763 :   CopyBytes(data_ + padded_payload_offset, payload->data(),
     332             :             static_cast<size_t>(payload->size()));
     333         763 : }
     334             : 
     335      216418 : std::vector<SerializedData::Reservation> SnapshotData::Reservations() const {
     336             :   uint32_t size = GetHeaderValue(kNumReservationsOffset);
     337      216418 :   std::vector<SerializedData::Reservation> reservations(size);
     338      216422 :   memcpy(reservations.data(), data_ + kHeaderSize,
     339             :          size * sizeof(SerializedData::Reservation));
     340      216422 :   return reservations;
     341             : }
     342             : 
     343      216389 : Vector<const byte> SnapshotData::Payload() const {
     344             :   uint32_t reservations_size =
     345      216389 :       GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
     346             :   uint32_t padded_payload_offset =
     347      216389 :       POINTER_SIZE_ALIGN(kHeaderSize + reservations_size);
     348      216389 :   const byte* payload = data_ + padded_payload_offset;
     349             :   uint32_t length = GetHeaderValue(kPayloadLengthOffset);
     350             :   DCHECK_EQ(data_ + size_, payload + length);
     351      216389 :   return Vector<const byte>(payload, length);
     352             : }
     353             : 
     354             : }  // namespace internal
     355      122004 : }  // namespace v8

Generated by: LCOV version 1.10