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