• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 #include "src/snapshot/shared-heap-serializer.h"
6 
7 #include "src/heap/heap-inl.h"
8 #include "src/heap/read-only-heap.h"
9 #include "src/objects/objects-inl.h"
10 #include "src/snapshot/read-only-serializer.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // static
CanBeInSharedOldSpace(HeapObject obj)16 bool SharedHeapSerializer::CanBeInSharedOldSpace(HeapObject obj) {
17   if (ReadOnlyHeap::Contains(obj)) return false;
18   if (obj.IsString()) {
19     return obj.IsInternalizedString() ||
20            String::IsInPlaceInternalizable(String::cast(obj));
21   }
22   return false;
23 }
24 
25 // static
ShouldBeInSharedHeapObjectCache(HeapObject obj)26 bool SharedHeapSerializer::ShouldBeInSharedHeapObjectCache(HeapObject obj) {
27   // To keep the shared heap object cache lean, only include objects that should
28   // not be duplicated. Currently, that is only internalized strings. In-place
29   // internalizable strings will still be allocated in the shared heap by the
30   // deserializer, but do not need to be kept alive forever in the cache.
31   if (CanBeInSharedOldSpace(obj)) {
32     if (obj.IsInternalizedString()) return true;
33   }
34   return false;
35 }
36 
SharedHeapSerializer(Isolate * isolate,Snapshot::SerializerFlags flags,ReadOnlySerializer * read_only_serializer)37 SharedHeapSerializer::SharedHeapSerializer(
38     Isolate* isolate, Snapshot::SerializerFlags flags,
39     ReadOnlySerializer* read_only_serializer)
40     : RootsSerializer(isolate, flags, RootIndex::kFirstStrongRoot),
41       read_only_serializer_(read_only_serializer)
42 #ifdef DEBUG
43       ,
44       serialized_objects_(isolate->heap())
45 #endif
46 {
47   if (ShouldReconstructSharedHeapObjectCacheForTesting()) {
48     ReconstructSharedHeapObjectCacheForTesting();
49   }
50 }
51 
~SharedHeapSerializer()52 SharedHeapSerializer::~SharedHeapSerializer() {
53   OutputStatistics("SharedHeapSerializer");
54 }
55 
FinalizeSerialization()56 void SharedHeapSerializer::FinalizeSerialization() {
57   // This is called after serialization of the startup and context snapshots
58   // which entries are added to the shared heap object cache. Terminate the
59   // cache with an undefined.
60   Object undefined = ReadOnlyRoots(isolate()).undefined_value();
61   VisitRootPointer(Root::kSharedHeapObjectCache, nullptr,
62                    FullObjectSlot(&undefined));
63 
64   // When FLAG_shared_string_table is true, all internalized and
65   // internalizable-in-place strings are in the shared heap.
66   SerializeStringTable(isolate()->string_table());
67   SerializeDeferredObjects();
68   Pad();
69 
70 #ifdef DEBUG
71   // Check that all serialized object are in shared heap and not RO. RO objects
72   // should be in the RO snapshot.
73   IdentityMap<int, base::DefaultAllocationPolicy>::IteratableScope it_scope(
74       &serialized_objects_);
75   for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
76     HeapObject obj = HeapObject::cast(it.key());
77     CHECK(CanBeInSharedOldSpace(obj));
78     CHECK(!ReadOnlyHeap::Contains(obj));
79   }
80 #endif
81 }
82 
SerializeUsingReadOnlyObjectCache(SnapshotByteSink * sink,Handle<HeapObject> obj)83 bool SharedHeapSerializer::SerializeUsingReadOnlyObjectCache(
84     SnapshotByteSink* sink, Handle<HeapObject> obj) {
85   return read_only_serializer_->SerializeUsingReadOnlyObjectCache(sink, obj);
86 }
87 
SerializeUsingSharedHeapObjectCache(SnapshotByteSink * sink,Handle<HeapObject> obj)88 bool SharedHeapSerializer::SerializeUsingSharedHeapObjectCache(
89     SnapshotByteSink* sink, Handle<HeapObject> obj) {
90   if (!ShouldBeInSharedHeapObjectCache(*obj)) return false;
91   int cache_index = SerializeInObjectCache(obj);
92 
93   // When testing deserialization of a snapshot from a live Isolate where there
94   // is also a shared Isolate, the shared object cache needs to be extended
95   // because the live isolate may have had new internalized strings that were
96   // not present in the startup snapshot to be serialized.
97   if (ShouldReconstructSharedHeapObjectCacheForTesting()) {
98     std::vector<Object>* existing_cache =
99         isolate()->shared_isolate()->shared_heap_object_cache();
100     const size_t existing_cache_size = existing_cache->size();
101     // This is strictly < because the existing cache contains the terminating
102     // undefined value, which the reconstructed cache does not.
103     DCHECK_LT(base::checked_cast<size_t>(cache_index), existing_cache_size);
104     if (base::checked_cast<size_t>(cache_index) == existing_cache_size - 1) {
105       ReadOnlyRoots roots(isolate());
106       DCHECK(existing_cache->back().IsUndefined(roots));
107       existing_cache->back() = *obj;
108       existing_cache->push_back(roots.undefined_value());
109     }
110   }
111 
112   sink->Put(kSharedHeapObjectCache, "SharedHeapObjectCache");
113   sink->PutInt(cache_index, "shared_heap_object_cache_index");
114   return true;
115 }
116 
SerializeStringTable(StringTable * string_table)117 void SharedHeapSerializer::SerializeStringTable(StringTable* string_table) {
118   // A StringTable is serialized as:
119   //
120   //   N : int
121   //   string 1
122   //   string 2
123   //   ...
124   //   string N
125   //
126   // Notably, the hashmap structure, including empty and deleted elements, is
127   // not serialized.
128 
129   sink_.PutInt(string_table->NumberOfElements(),
130                "String table number of elements");
131 
132   // Custom RootVisitor which walks the string table, but only serializes the
133   // string entries. This is an inline class to be able to access the non-public
134   // SerializeObject method.
135   class SharedHeapSerializerStringTableVisitor : public RootVisitor {
136    public:
137     explicit SharedHeapSerializerStringTableVisitor(
138         SharedHeapSerializer* serializer)
139         : serializer_(serializer) {}
140 
141     void VisitRootPointers(Root root, const char* description,
142                            FullObjectSlot start, FullObjectSlot end) override {
143       UNREACHABLE();
144     }
145 
146     void VisitRootPointers(Root root, const char* description,
147                            OffHeapObjectSlot start,
148                            OffHeapObjectSlot end) override {
149       DCHECK_EQ(root, Root::kStringTable);
150       Isolate* isolate = serializer_->isolate();
151       for (OffHeapObjectSlot current = start; current < end; ++current) {
152         Object obj = current.load(isolate);
153         if (obj.IsHeapObject()) {
154           DCHECK(obj.IsInternalizedString());
155           serializer_->SerializeObject(handle(HeapObject::cast(obj), isolate));
156         }
157       }
158     }
159 
160    private:
161     SharedHeapSerializer* serializer_;
162   };
163 
164   SharedHeapSerializerStringTableVisitor string_table_visitor(this);
165   isolate()->string_table()->IterateElements(&string_table_visitor);
166 }
167 
SerializeObjectImpl(Handle<HeapObject> obj)168 void SharedHeapSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
169   // Objects in the shared heap cannot depend on per-Isolate roots but can
170   // depend on RO roots since sharing objects requires sharing the RO space.
171   DCHECK(CanBeInSharedOldSpace(*obj) || ReadOnlyHeap::Contains(*obj));
172   {
173     DisallowGarbageCollection no_gc;
174     HeapObject raw = *obj;
175     if (SerializeHotObject(raw)) return;
176     if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return;
177   }
178   if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
179   {
180     DisallowGarbageCollection no_gc;
181     HeapObject raw = *obj;
182     if (SerializeBackReference(raw)) return;
183     CheckRehashability(raw);
184 
185     DCHECK(!ReadOnlyHeap::Contains(raw));
186   }
187 
188   ObjectSerializer object_serializer(this, obj, &sink_);
189   object_serializer.Serialize();
190 
191 #ifdef DEBUG
192   CHECK_NULL(serialized_objects_.Find(obj));
193   // There's no "IdentitySet", so use an IdentityMap with a value that is
194   // later ignored.
195   serialized_objects_.Insert(obj, 0);
196 #endif
197 }
198 
ShouldReconstructSharedHeapObjectCacheForTesting() const199 bool SharedHeapSerializer::ShouldReconstructSharedHeapObjectCacheForTesting()
200     const {
201   // When the live Isolate being serialized is not a client Isolate, there's no
202   // need to reconstruct the shared heap object cache because it is not actually
203   // shared.
204   return reconstruct_read_only_and_shared_object_caches_for_testing() &&
205          isolate()->shared_isolate() != nullptr;
206 }
207 
ReconstructSharedHeapObjectCacheForTesting()208 void SharedHeapSerializer::ReconstructSharedHeapObjectCacheForTesting() {
209   std::vector<Object>* cache =
210       isolate()->shared_isolate()->shared_heap_object_cache();
211   // Don't reconstruct the final element, which is always undefined and marks
212   // the end of the cache, since serializing the live Isolate may extend the
213   // shared object cache.
214   for (size_t i = 0, size = cache->size(); i < size - 1; i++) {
215     Handle<HeapObject> obj(HeapObject::cast(cache->at(i)), isolate());
216     DCHECK(ShouldBeInSharedHeapObjectCache(*obj));
217     int cache_index = SerializeInObjectCache(obj);
218     USE(cache_index);
219     DCHECK_EQ(cache_index, i);
220   }
221   DCHECK(cache->back().IsUndefined(isolate()));
222 }
223 
224 }  // namespace internal
225 }  // namespace v8
226