11cb0ef41Sopenharmony_ci// Copyright 2021 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/snapshot/shared-heap-serializer.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"
81cb0ef41Sopenharmony_ci#include "src/heap/read-only-heap.h"
91cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
101cb0ef41Sopenharmony_ci#include "src/snapshot/read-only-serializer.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace v8 {
131cb0ef41Sopenharmony_cinamespace internal {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci// static
161cb0ef41Sopenharmony_cibool SharedHeapSerializer::CanBeInSharedOldSpace(HeapObject obj) {
171cb0ef41Sopenharmony_ci  if (ReadOnlyHeap::Contains(obj)) return false;
181cb0ef41Sopenharmony_ci  if (obj.IsString()) {
191cb0ef41Sopenharmony_ci    return obj.IsInternalizedString() ||
201cb0ef41Sopenharmony_ci           String::IsInPlaceInternalizable(String::cast(obj));
211cb0ef41Sopenharmony_ci  }
221cb0ef41Sopenharmony_ci  return false;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// static
261cb0ef41Sopenharmony_cibool SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(HeapObject obj) {
271cb0ef41Sopenharmony_ci  // To keep the shared heap object cache lean, only include objects that should
281cb0ef41Sopenharmony_ci  // not be duplicated. Currently, that is only internalized strings. In-place
291cb0ef41Sopenharmony_ci  // internalizable strings will still be allocated in the shared heap by the
301cb0ef41Sopenharmony_ci  // deserializer, but do not need to be kept alive forever in the cache.
311cb0ef41Sopenharmony_ci  if (CanBeInSharedOldSpace(obj)) {
321cb0ef41Sopenharmony_ci    if (obj.IsInternalizedString()) return true;
331cb0ef41Sopenharmony_ci  }
341cb0ef41Sopenharmony_ci  return false;
351cb0ef41Sopenharmony_ci}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciSharedHeapSerializer::SharedHeapSerializer(
381cb0ef41Sopenharmony_ci    Isolate* isolate, Snapshot::SerializerFlags flags,
391cb0ef41Sopenharmony_ci    ReadOnlySerializer* read_only_serializer)
401cb0ef41Sopenharmony_ci    : RootsSerializer(isolate, flags, RootIndex::kFirstStrongRoot),
411cb0ef41Sopenharmony_ci      read_only_serializer_(read_only_serializer)
421cb0ef41Sopenharmony_ci#ifdef DEBUG
431cb0ef41Sopenharmony_ci      ,
441cb0ef41Sopenharmony_ci      serialized_objects_(isolate->heap())
451cb0ef41Sopenharmony_ci#endif
461cb0ef41Sopenharmony_ci{
471cb0ef41Sopenharmony_ci  if (ShouldReconstructSharedHeapObjectCacheForTesting()) {
481cb0ef41Sopenharmony_ci    ReconstructSharedHeapObjectCacheForTesting();
491cb0ef41Sopenharmony_ci  }
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciSharedHeapSerializer::~SharedHeapSerializer() {
531cb0ef41Sopenharmony_ci  OutputStatistics("SharedHeapSerializer");
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_civoid SharedHeapSerializer::FinalizeSerialization() {
571cb0ef41Sopenharmony_ci  // This is called after serialization of the startup and context snapshots
581cb0ef41Sopenharmony_ci  // which entries are added to the shared heap object cache. Terminate the
591cb0ef41Sopenharmony_ci  // cache with an undefined.
601cb0ef41Sopenharmony_ci  Object undefined = ReadOnlyRoots(isolate()).undefined_value();
611cb0ef41Sopenharmony_ci  VisitRootPointer(Root::kSharedHeapObjectCache, nullptr,
621cb0ef41Sopenharmony_ci                   FullObjectSlot(&undefined));
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  // When FLAG_shared_string_table is true, all internalized and
651cb0ef41Sopenharmony_ci  // internalizable-in-place strings are in the shared heap.
661cb0ef41Sopenharmony_ci  SerializeStringTable(isolate()->string_table());
671cb0ef41Sopenharmony_ci  SerializeDeferredObjects();
681cb0ef41Sopenharmony_ci  Pad();
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci#ifdef DEBUG
711cb0ef41Sopenharmony_ci  // Check that all serialized object are in shared heap and not RO. RO objects
721cb0ef41Sopenharmony_ci  // should be in the RO snapshot.
731cb0ef41Sopenharmony_ci  IdentityMap<int, base::DefaultAllocationPolicy>::IteratableScope it_scope(
741cb0ef41Sopenharmony_ci      &serialized_objects_);
751cb0ef41Sopenharmony_ci  for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
761cb0ef41Sopenharmony_ci    HeapObject obj = HeapObject::cast(it.key());
771cb0ef41Sopenharmony_ci    CHECK(CanBeInSharedOldSpace(obj));
781cb0ef41Sopenharmony_ci    CHECK(!ReadOnlyHeap::Contains(obj));
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci#endif
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_cibool SharedHeapSerializer::SerializeUsingReadOnlyObjectCache(
841cb0ef41Sopenharmony_ci    SnapshotByteSink* sink, Handle<HeapObject> obj) {
851cb0ef41Sopenharmony_ci  return read_only_serializer_->SerializeUsingReadOnlyObjectCache(sink, obj);
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_cibool SharedHeapSerializer::SerializeUsingSharedHeapObjectCache(
891cb0ef41Sopenharmony_ci    SnapshotByteSink* sink, Handle<HeapObject> obj) {
901cb0ef41Sopenharmony_ci  if (!ShouldBeInSharedHeapObjectCache(*obj)) return false;
911cb0ef41Sopenharmony_ci  int cache_index = SerializeInObjectCache(obj);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  // When testing deserialization of a snapshot from a live Isolate where there
941cb0ef41Sopenharmony_ci  // is also a shared Isolate, the shared object cache needs to be extended
951cb0ef41Sopenharmony_ci  // because the live isolate may have had new internalized strings that were
961cb0ef41Sopenharmony_ci  // not present in the startup snapshot to be serialized.
971cb0ef41Sopenharmony_ci  if (ShouldReconstructSharedHeapObjectCacheForTesting()) {
981cb0ef41Sopenharmony_ci    std::vector<Object>* existing_cache =
991cb0ef41Sopenharmony_ci        isolate()->shared_isolate()->shared_heap_object_cache();
1001cb0ef41Sopenharmony_ci    const size_t existing_cache_size = existing_cache->size();
1011cb0ef41Sopenharmony_ci    // This is strictly < because the existing cache contains the terminating
1021cb0ef41Sopenharmony_ci    // undefined value, which the reconstructed cache does not.
1031cb0ef41Sopenharmony_ci    DCHECK_LT(base::checked_cast<size_t>(cache_index), existing_cache_size);
1041cb0ef41Sopenharmony_ci    if (base::checked_cast<size_t>(cache_index) == existing_cache_size - 1) {
1051cb0ef41Sopenharmony_ci      ReadOnlyRoots roots(isolate());
1061cb0ef41Sopenharmony_ci      DCHECK(existing_cache->back().IsUndefined(roots));
1071cb0ef41Sopenharmony_ci      existing_cache->back() = *obj;
1081cb0ef41Sopenharmony_ci      existing_cache->push_back(roots.undefined_value());
1091cb0ef41Sopenharmony_ci    }
1101cb0ef41Sopenharmony_ci  }
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  sink->Put(kSharedHeapObjectCache, "SharedHeapObjectCache");
1131cb0ef41Sopenharmony_ci  sink->PutInt(cache_index, "shared_heap_object_cache_index");
1141cb0ef41Sopenharmony_ci  return true;
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_civoid SharedHeapSerializer::SerializeStringTable(StringTable* string_table) {
1181cb0ef41Sopenharmony_ci  // A StringTable is serialized as:
1191cb0ef41Sopenharmony_ci  //
1201cb0ef41Sopenharmony_ci  //   N : int
1211cb0ef41Sopenharmony_ci  //   string 1
1221cb0ef41Sopenharmony_ci  //   string 2
1231cb0ef41Sopenharmony_ci  //   ...
1241cb0ef41Sopenharmony_ci  //   string N
1251cb0ef41Sopenharmony_ci  //
1261cb0ef41Sopenharmony_ci  // Notably, the hashmap structure, including empty and deleted elements, is
1271cb0ef41Sopenharmony_ci  // not serialized.
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  sink_.PutInt(string_table->NumberOfElements(),
1301cb0ef41Sopenharmony_ci               "String table number of elements");
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  // Custom RootVisitor which walks the string table, but only serializes the
1331cb0ef41Sopenharmony_ci  // string entries. This is an inline class to be able to access the non-public
1341cb0ef41Sopenharmony_ci  // SerializeObject method.
1351cb0ef41Sopenharmony_ci  class SharedHeapSerializerStringTableVisitor : public RootVisitor {
1361cb0ef41Sopenharmony_ci   public:
1371cb0ef41Sopenharmony_ci    explicit SharedHeapSerializerStringTableVisitor(
1381cb0ef41Sopenharmony_ci        SharedHeapSerializer* serializer)
1391cb0ef41Sopenharmony_ci        : serializer_(serializer) {}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    void VisitRootPointers(Root root, const char* description,
1421cb0ef41Sopenharmony_ci                           FullObjectSlot start, FullObjectSlot end) override {
1431cb0ef41Sopenharmony_ci      UNREACHABLE();
1441cb0ef41Sopenharmony_ci    }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci    void VisitRootPointers(Root root, const char* description,
1471cb0ef41Sopenharmony_ci                           OffHeapObjectSlot start,
1481cb0ef41Sopenharmony_ci                           OffHeapObjectSlot end) override {
1491cb0ef41Sopenharmony_ci      DCHECK_EQ(root, Root::kStringTable);
1501cb0ef41Sopenharmony_ci      Isolate* isolate = serializer_->isolate();
1511cb0ef41Sopenharmony_ci      for (OffHeapObjectSlot current = start; current < end; ++current) {
1521cb0ef41Sopenharmony_ci        Object obj = current.load(isolate);
1531cb0ef41Sopenharmony_ci        if (obj.IsHeapObject()) {
1541cb0ef41Sopenharmony_ci          DCHECK(obj.IsInternalizedString());
1551cb0ef41Sopenharmony_ci          serializer_->SerializeObject(handle(HeapObject::cast(obj), isolate));
1561cb0ef41Sopenharmony_ci        }
1571cb0ef41Sopenharmony_ci      }
1581cb0ef41Sopenharmony_ci    }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci   private:
1611cb0ef41Sopenharmony_ci    SharedHeapSerializer* serializer_;
1621cb0ef41Sopenharmony_ci  };
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  SharedHeapSerializerStringTableVisitor string_table_visitor(this);
1651cb0ef41Sopenharmony_ci  isolate()->string_table()->IterateElements(&string_table_visitor);
1661cb0ef41Sopenharmony_ci}
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_civoid SharedHeapSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
1691cb0ef41Sopenharmony_ci  // Objects in the shared heap cannot depend on per-Isolate roots but can
1701cb0ef41Sopenharmony_ci  // depend on RO roots since sharing objects requires sharing the RO space.
1711cb0ef41Sopenharmony_ci  DCHECK(CanBeInSharedOldSpace(*obj) || ReadOnlyHeap::Contains(*obj));
1721cb0ef41Sopenharmony_ci  {
1731cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
1741cb0ef41Sopenharmony_ci    HeapObject raw = *obj;
1751cb0ef41Sopenharmony_ci    if (SerializeHotObject(raw)) return;
1761cb0ef41Sopenharmony_ci    if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return;
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci  if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
1791cb0ef41Sopenharmony_ci  {
1801cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
1811cb0ef41Sopenharmony_ci    HeapObject raw = *obj;
1821cb0ef41Sopenharmony_ci    if (SerializeBackReference(raw)) return;
1831cb0ef41Sopenharmony_ci    CheckRehashability(raw);
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci    DCHECK(!ReadOnlyHeap::Contains(raw));
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  ObjectSerializer object_serializer(this, obj, &sink_);
1891cb0ef41Sopenharmony_ci  object_serializer.Serialize();
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci#ifdef DEBUG
1921cb0ef41Sopenharmony_ci  CHECK_NULL(serialized_objects_.Find(obj));
1931cb0ef41Sopenharmony_ci  // There's no "IdentitySet", so use an IdentityMap with a value that is
1941cb0ef41Sopenharmony_ci  // later ignored.
1951cb0ef41Sopenharmony_ci  serialized_objects_.Insert(obj, 0);
1961cb0ef41Sopenharmony_ci#endif
1971cb0ef41Sopenharmony_ci}
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_cibool SharedHeapSerializer::ShouldReconstructSharedHeapObjectCacheForTesting()
2001cb0ef41Sopenharmony_ci    const {
2011cb0ef41Sopenharmony_ci  // When the live Isolate being serialized is not a client Isolate, there's no
2021cb0ef41Sopenharmony_ci  // need to reconstruct the shared heap object cache because it is not actually
2031cb0ef41Sopenharmony_ci  // shared.
2041cb0ef41Sopenharmony_ci  return reconstruct_read_only_and_shared_object_caches_for_testing() &&
2051cb0ef41Sopenharmony_ci         isolate()->shared_isolate() != nullptr;
2061cb0ef41Sopenharmony_ci}
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_civoid SharedHeapSerializer::ReconstructSharedHeapObjectCacheForTesting() {
2091cb0ef41Sopenharmony_ci  std::vector<Object>* cache =
2101cb0ef41Sopenharmony_ci      isolate()->shared_isolate()->shared_heap_object_cache();
2111cb0ef41Sopenharmony_ci  // Don't reconstruct the final element, which is always undefined and marks
2121cb0ef41Sopenharmony_ci  // the end of the cache, since serializing the live Isolate may extend the
2131cb0ef41Sopenharmony_ci  // shared object cache.
2141cb0ef41Sopenharmony_ci  for (size_t i = 0, size = cache->size(); i < size - 1; i++) {
2151cb0ef41Sopenharmony_ci    Handle<HeapObject> obj(HeapObject::cast(cache->at(i)), isolate());
2161cb0ef41Sopenharmony_ci    DCHECK(ShouldBeInSharedHeapObjectCache(*obj));
2171cb0ef41Sopenharmony_ci    int cache_index = SerializeInObjectCache(obj);
2181cb0ef41Sopenharmony_ci    USE(cache_index);
2191cb0ef41Sopenharmony_ci    DCHECK_EQ(cache_index, i);
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci  DCHECK(cache->back().IsUndefined(isolate()));
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ci}  // namespace internal
2251cb0ef41Sopenharmony_ci}  // namespace v8
226