• 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 
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