• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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