LCOV - code coverage report
Current view: top level - src/snapshot - snapshot-common.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 145 147 98.6 %
Date: 2019-02-19 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.10