1 // Copyright 2016 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/startup-serializer.h"
6
7 #include "src/api/api.h"
8 #include "src/deoptimizer/deoptimizer.h"
9 #include "src/execution/v8threads.h"
10 #include "src/handles/global-handles.h"
11 #include "src/heap/heap-inl.h"
12 #include "src/heap/read-only-heap.h"
13 #include "src/objects/contexts.h"
14 #include "src/objects/foreign-inl.h"
15 #include "src/objects/objects-inl.h"
16 #include "src/objects/slots.h"
17 #include "src/snapshot/read-only-serializer.h"
18
19 namespace v8 {
20 namespace internal {
21
22 namespace {
23
24 // The isolate roots may not point at context-specific objects during
25 // serialization.
26 class SanitizeIsolateScope final {
27 public:
SanitizeIsolateScope(Isolate * isolate,bool allow_active_isolate_for_testing,const DisallowGarbageCollection & no_gc)28 SanitizeIsolateScope(Isolate* isolate, bool allow_active_isolate_for_testing,
29 const DisallowGarbageCollection& no_gc)
30 : isolate_(isolate),
31 feedback_vectors_for_profiling_tools_(
32 isolate->heap()->feedback_vectors_for_profiling_tools()),
33 detached_contexts_(isolate->heap()->detached_contexts()) {
34 #ifdef DEBUG
35 if (!allow_active_isolate_for_testing) {
36 // These should already be empty when creating a real snapshot.
37 DCHECK_EQ(feedback_vectors_for_profiling_tools_,
38 ReadOnlyRoots(isolate).undefined_value());
39 DCHECK_EQ(detached_contexts_,
40 ReadOnlyRoots(isolate).empty_weak_array_list());
41 }
42 #endif
43
44 isolate->SetFeedbackVectorsForProfilingTools(
45 ReadOnlyRoots(isolate).undefined_value());
46 isolate->heap()->SetDetachedContexts(
47 ReadOnlyRoots(isolate).empty_weak_array_list());
48 }
49
~SanitizeIsolateScope()50 ~SanitizeIsolateScope() {
51 // Restore saved fields.
52 isolate_->SetFeedbackVectorsForProfilingTools(
53 feedback_vectors_for_profiling_tools_);
54 isolate_->heap()->SetDetachedContexts(detached_contexts_);
55 }
56
57 private:
58 Isolate* isolate_;
59 const Object feedback_vectors_for_profiling_tools_;
60 const WeakArrayList detached_contexts_;
61 };
62
63 } // namespace
64
StartupSerializer(Isolate * isolate,Snapshot::SerializerFlags flags,ReadOnlySerializer * read_only_serializer)65 StartupSerializer::StartupSerializer(Isolate* isolate,
66 Snapshot::SerializerFlags flags,
67 ReadOnlySerializer* read_only_serializer)
68 : RootsSerializer(isolate, flags, RootIndex::kFirstStrongRoot),
69 read_only_serializer_(read_only_serializer),
70 accessor_infos_(isolate->heap()),
71 call_handler_infos_(isolate->heap()) {
72 InitializeCodeAddressMap();
73 }
74
~StartupSerializer()75 StartupSerializer::~StartupSerializer() {
76 for (Handle<AccessorInfo> info : accessor_infos_) {
77 RestoreExternalReferenceRedirector(isolate(), info);
78 }
79 for (Handle<CallHandlerInfo> info : call_handler_infos_) {
80 RestoreExternalReferenceRedirector(isolate(), info);
81 }
82 OutputStatistics("StartupSerializer");
83 }
84
85 #ifdef DEBUG
86 namespace {
87
IsUnexpectedCodeObject(Isolate * isolate,HeapObject obj)88 bool IsUnexpectedCodeObject(Isolate* isolate, HeapObject obj) {
89 if (!obj.IsCode()) return false;
90
91 Code code = Code::cast(obj);
92 if (code.kind() == CodeKind::REGEXP) return false;
93 if (!code.is_builtin()) return true;
94 if (code.is_off_heap_trampoline()) return false;
95
96 // An on-heap builtin. We only expect this for the interpreter entry
97 // trampoline copy stored on the root list and transitively called builtins.
98 // See Heap::interpreter_entry_trampoline_for_profiling.
99
100 switch (code.builtin_index()) {
101 case Builtins::kAbort:
102 case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
103 case Builtins::kInterpreterEntryTrampoline:
104 case Builtins::kRecordWrite:
105 return false;
106 default:
107 return true;
108 }
109
110 UNREACHABLE();
111 }
112
113 } // namespace
114 #endif // DEBUG
115
SerializeObjectImpl(Handle<HeapObject> obj)116 void StartupSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
117 #ifdef DEBUG
118 if (obj->IsJSFunction()) {
119 v8::base::OS::PrintError("Reference stack:\n");
120 PrintStack(std::cerr);
121 obj->Print(std::cerr);
122 FATAL(
123 "JSFunction should be added through the context snapshot instead of "
124 "the isolate snapshot");
125 }
126 #endif // DEBUG
127 DCHECK(!IsUnexpectedCodeObject(isolate(), *obj));
128
129 if (SerializeHotObject(obj)) return;
130 if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) return;
131 if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
132 if (SerializeBackReference(obj)) return;
133
134 bool use_simulator = false;
135 #ifdef USE_SIMULATOR
136 use_simulator = true;
137 #endif
138
139 if (use_simulator && obj->IsAccessorInfo()) {
140 // Wipe external reference redirects in the accessor info.
141 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(obj);
142 Address original_address =
143 Foreign::cast(info->getter()).foreign_address(isolate());
144 Foreign::cast(info->js_getter())
145 .set_foreign_address(isolate(), original_address);
146 accessor_infos_.Push(*info);
147 } else if (use_simulator && obj->IsCallHandlerInfo()) {
148 Handle<CallHandlerInfo> info = Handle<CallHandlerInfo>::cast(obj);
149 Address original_address =
150 Foreign::cast(info->callback()).foreign_address(isolate());
151 Foreign::cast(info->js_callback())
152 .set_foreign_address(isolate(), original_address);
153 call_handler_infos_.Push(*info);
154 } else if (obj->IsScript() && Handle<Script>::cast(obj)->IsUserJavaScript()) {
155 Handle<Script>::cast(obj)->set_context_data(
156 ReadOnlyRoots(isolate()).uninitialized_symbol());
157 } else if (obj->IsSharedFunctionInfo()) {
158 // Clear inferred name for native functions.
159 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(obj);
160 if (!shared->IsSubjectToDebugging() && shared->HasUncompiledData()) {
161 shared->uncompiled_data().set_inferred_name(
162 ReadOnlyRoots(isolate()).empty_string());
163 }
164 }
165
166 CheckRehashability(*obj);
167
168 // Object has not yet been serialized. Serialize it here.
169 DCHECK(!ReadOnlyHeap::Contains(*obj));
170 ObjectSerializer object_serializer(this, obj, &sink_);
171 object_serializer.Serialize();
172 }
173
SerializeWeakReferencesAndDeferred()174 void StartupSerializer::SerializeWeakReferencesAndDeferred() {
175 // This comes right after serialization of the context snapshot, where we
176 // add entries to the startup object cache of the startup snapshot. Add
177 // one entry with 'undefined' to terminate the startup object cache.
178 Object undefined = ReadOnlyRoots(isolate()).undefined_value();
179 VisitRootPointer(Root::kStartupObjectCache, nullptr,
180 FullObjectSlot(&undefined));
181
182 SerializeStringTable(isolate()->string_table());
183
184 isolate()->heap()->IterateWeakRoots(
185 this, base::EnumSet<SkipRoot>{SkipRoot::kUnserializable});
186 SerializeDeferredObjects();
187 Pad();
188 }
189
SerializeStringTable(StringTable * string_table)190 void StartupSerializer::SerializeStringTable(StringTable* string_table) {
191 // A StringTable is serialized as:
192 //
193 // N : int
194 // string 1
195 // string 2
196 // ...
197 // string N
198 //
199 // Notably, the hashmap structure, including empty and deleted elements, is
200 // not serialized.
201
202 sink_.PutInt(isolate()->string_table()->NumberOfElements(),
203 "String table number of elements");
204
205 // Custom RootVisitor which walks the string table, but only serializes the
206 // string entries. This is an inline class to be able to access the non-public
207 // SerializeObject method.
208 class StartupSerializerStringTableVisitor : public RootVisitor {
209 public:
210 explicit StartupSerializerStringTableVisitor(StartupSerializer* serializer)
211 : serializer_(serializer) {}
212
213 void VisitRootPointers(Root root, const char* description,
214 FullObjectSlot start, FullObjectSlot end) override {
215 UNREACHABLE();
216 }
217
218 void VisitRootPointers(Root root, const char* description,
219 OffHeapObjectSlot start,
220 OffHeapObjectSlot end) override {
221 DCHECK_EQ(root, Root::kStringTable);
222 Isolate* isolate = serializer_->isolate();
223 for (OffHeapObjectSlot current = start; current < end; ++current) {
224 Object obj = current.load(isolate);
225 if (obj.IsHeapObject()) {
226 DCHECK(obj.IsInternalizedString());
227 serializer_->SerializeObject(handle(HeapObject::cast(obj), isolate));
228 }
229 }
230 }
231
232 private:
233 StartupSerializer* serializer_;
234 };
235
236 StartupSerializerStringTableVisitor string_table_visitor(this);
237 isolate()->string_table()->IterateElements(&string_table_visitor);
238 }
239
SerializeStrongReferences(const DisallowGarbageCollection & no_gc)240 void StartupSerializer::SerializeStrongReferences(
241 const DisallowGarbageCollection& no_gc) {
242 Isolate* isolate = this->isolate();
243 // No active threads.
244 CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
245
246 SanitizeIsolateScope sanitize_isolate(
247 isolate, allow_active_isolate_for_testing(), no_gc);
248
249 // Visit smi roots and immortal immovables first to make sure they end up in
250 // the first page.
251 isolate->heap()->IterateSmiRoots(this);
252 isolate->heap()->IterateRoots(
253 this,
254 base::EnumSet<SkipRoot>{SkipRoot::kUnserializable, SkipRoot::kWeak});
255 }
256
SerializedHandleChecker(Isolate * isolate,std::vector<Context> * contexts)257 SerializedHandleChecker::SerializedHandleChecker(Isolate* isolate,
258 std::vector<Context>* contexts)
259 : isolate_(isolate) {
260 AddToSet(isolate->heap()->serialized_objects());
261 for (auto const& context : *contexts) {
262 AddToSet(context.serialized_objects());
263 }
264 }
265
SerializeUsingReadOnlyObjectCache(SnapshotByteSink * sink,Handle<HeapObject> obj)266 bool StartupSerializer::SerializeUsingReadOnlyObjectCache(
267 SnapshotByteSink* sink, Handle<HeapObject> obj) {
268 return read_only_serializer_->SerializeUsingReadOnlyObjectCache(sink, obj);
269 }
270
SerializeUsingStartupObjectCache(SnapshotByteSink * sink,Handle<HeapObject> obj)271 void StartupSerializer::SerializeUsingStartupObjectCache(
272 SnapshotByteSink* sink, Handle<HeapObject> obj) {
273 int cache_index = SerializeInObjectCache(obj);
274 sink->Put(kStartupObjectCache, "StartupObjectCache");
275 sink->PutInt(cache_index, "startup_object_cache_index");
276 }
277
CheckNoDirtyFinalizationRegistries()278 void StartupSerializer::CheckNoDirtyFinalizationRegistries() {
279 Isolate* isolate = this->isolate();
280 CHECK(isolate->heap()->dirty_js_finalization_registries_list().IsUndefined(
281 isolate));
282 CHECK(
283 isolate->heap()->dirty_js_finalization_registries_list_tail().IsUndefined(
284 isolate));
285 }
286
AddToSet(FixedArray serialized)287 void SerializedHandleChecker::AddToSet(FixedArray serialized) {
288 int length = serialized.length();
289 for (int i = 0; i < length; i++) serialized_.insert(serialized.get(i));
290 }
291
VisitRootPointers(Root root,const char * description,FullObjectSlot start,FullObjectSlot end)292 void SerializedHandleChecker::VisitRootPointers(Root root,
293 const char* description,
294 FullObjectSlot start,
295 FullObjectSlot end) {
296 for (FullObjectSlot p = start; p < end; ++p) {
297 if (serialized_.find(*p) != serialized_.end()) continue;
298 PrintF("%s handle not serialized: ",
299 root == Root::kGlobalHandles ? "global" : "eternal");
300 (*p).Print();
301 PrintF("\n");
302 ok_ = false;
303 }
304 }
305
CheckGlobalAndEternalHandles()306 bool SerializedHandleChecker::CheckGlobalAndEternalHandles() {
307 isolate_->global_handles()->IterateAllRoots(this);
308 isolate_->eternal_handles()->IterateAllRoots(this);
309 return ok_;
310 }
311
312 } // namespace internal
313 } // namespace v8
314