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/objects-inl.h"
8 #include "src/v8threads.h"
9 
10 namespace v8 {
11 namespace internal {
12 
StartupSerializer(Isolate * isolate,v8::SnapshotCreator::FunctionCodeHandling function_code_handling)13 StartupSerializer::StartupSerializer(
14     Isolate* isolate,
15     v8::SnapshotCreator::FunctionCodeHandling function_code_handling)
16     : Serializer(isolate),
17       clear_function_code_(function_code_handling ==
18                            v8::SnapshotCreator::FunctionCodeHandling::kClear),
19       serializing_builtins_(false) {
20   InitializeCodeAddressMap();
21 }
22 
~StartupSerializer()23 StartupSerializer::~StartupSerializer() {
24   OutputStatistics("StartupSerializer");
25 }
26 
SerializeObject(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)27 void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
28                                         WhereToPoint where_to_point, int skip) {
29   DCHECK(!obj->IsJSFunction());
30 
31   if (clear_function_code_) {
32     if (obj->IsCode()) {
33       Code* code = Code::cast(obj);
34       // If the function code is compiled (either as native code or bytecode),
35       // replace it with lazy-compile builtin. Only exception is when we are
36       // serializing the canonical interpreter-entry-trampoline builtin.
37       if (code->kind() == Code::FUNCTION ||
38           (!serializing_builtins_ &&
39            code->is_interpreter_trampoline_builtin())) {
40         obj = isolate()->builtins()->builtin(Builtins::kCompileLazy);
41       }
42     } else if (obj->IsBytecodeArray()) {
43       obj = isolate()->heap()->undefined_value();
44     }
45   } else if (obj->IsCode()) {
46     Code* code = Code::cast(obj);
47     if (code->kind() == Code::FUNCTION) {
48       code->ClearInlineCaches();
49       code->set_profiler_ticks(0);
50     }
51   }
52 
53   if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
54 
55   int root_index = root_index_map_.Lookup(obj);
56   // We can only encode roots as such if it has already been serialized.
57   // That applies to root indices below the wave front.
58   if (root_index != RootIndexMap::kInvalidRootIndex) {
59     if (root_has_been_serialized_.test(root_index)) {
60       PutRoot(root_index, obj, how_to_code, where_to_point, skip);
61       return;
62     }
63   }
64 
65   if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
66 
67   FlushSkip(skip);
68 
69   // Object has not yet been serialized.  Serialize it here.
70   ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
71                                      where_to_point);
72   object_serializer.Serialize();
73 
74   if (serializing_immortal_immovables_roots_ &&
75       root_index != RootIndexMap::kInvalidRootIndex) {
76     // Make sure that the immortal immovable root has been included in the first
77     // chunk of its reserved space , so that it is deserialized onto the first
78     // page of its space and stays immortal immovable.
79     SerializerReference ref = reference_map_.Lookup(obj);
80     CHECK(ref.is_back_reference() && ref.chunk_index() == 0);
81   }
82 }
83 
SerializeWeakReferencesAndDeferred()84 void StartupSerializer::SerializeWeakReferencesAndDeferred() {
85   // This comes right after serialization of the partial snapshot, where we
86   // add entries to the partial snapshot cache of the startup snapshot. Add
87   // one entry with 'undefined' to terminate the partial snapshot cache.
88   Object* undefined = isolate()->heap()->undefined_value();
89   VisitPointer(&undefined);
90   isolate()->heap()->IterateWeakRoots(this, VISIT_ALL);
91   SerializeDeferredObjects();
92   Pad();
93 }
94 
PartialSnapshotCacheIndex(HeapObject * heap_object)95 int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
96   int index;
97   if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
98     // This object is not part of the partial snapshot cache yet. Add it to the
99     // startup snapshot so we can refer to it via partial snapshot index from
100     // the partial snapshot.
101     VisitPointer(reinterpret_cast<Object**>(&heap_object));
102   }
103   return index;
104 }
105 
Synchronize(VisitorSynchronization::SyncTag tag)106 void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
107   // We expect the builtins tag after builtins have been serialized.
108   DCHECK(!serializing_builtins_ || tag == VisitorSynchronization::kBuiltins);
109   serializing_builtins_ = (tag == VisitorSynchronization::kHandleScope);
110   sink_.Put(kSynchronize, "Synchronize");
111 }
112 
SerializeStrongReferences()113 void StartupSerializer::SerializeStrongReferences() {
114   Isolate* isolate = this->isolate();
115   // No active threads.
116   CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
117   // No active or weak handles.
118   CHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
119   CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles());
120   CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles());
121   // We don't support serializing installed extensions.
122   CHECK(!isolate->has_installed_extensions());
123   // First visit immortal immovables to make sure they end up in the first page.
124   serializing_immortal_immovables_roots_ = true;
125   isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
126   // Check that immortal immovable roots are allocated on the first page.
127   CHECK(HasNotExceededFirstPageOfEachSpace());
128   serializing_immortal_immovables_roots_ = false;
129   // Visit the rest of the strong roots.
130   // Clear the stack limits to make the snapshot reproducible.
131   // Reset it again afterwards.
132   isolate->heap()->ClearStackLimits();
133   isolate->heap()->IterateSmiRoots(this);
134   isolate->heap()->SetStackLimits();
135 
136   isolate->heap()->IterateStrongRoots(this,
137                                       VISIT_ONLY_STRONG_FOR_SERIALIZATION);
138 }
139 
VisitPointers(Object ** start,Object ** end)140 void StartupSerializer::VisitPointers(Object** start, Object** end) {
141   if (start == isolate()->heap()->roots_array_start()) {
142     // Serializing the root list needs special handling:
143     // - The first pass over the root list only serializes immortal immovables.
144     // - The second pass over the root list serializes the rest.
145     // - Only root list elements that have been fully serialized can be
146     //   referenced via as root by using kRootArray bytecodes.
147     int skip = 0;
148     for (Object** current = start; current < end; current++) {
149       int root_index = static_cast<int>(current - start);
150       if (RootShouldBeSkipped(root_index)) {
151         skip += kPointerSize;
152         continue;
153       } else {
154         if ((*current)->IsSmi()) {
155           FlushSkip(skip);
156           PutSmi(Smi::cast(*current));
157         } else {
158           SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject,
159                           skip);
160         }
161         root_has_been_serialized_.set(root_index);
162         skip = 0;
163       }
164     }
165     FlushSkip(skip);
166   } else {
167     Serializer::VisitPointers(start, end);
168   }
169 }
170 
RootShouldBeSkipped(int root_index)171 bool StartupSerializer::RootShouldBeSkipped(int root_index) {
172   if (root_index == Heap::kStackLimitRootIndex ||
173       root_index == Heap::kRealStackLimitRootIndex) {
174     return true;
175   }
176   return Heap::RootIsImmortalImmovable(root_index) !=
177          serializing_immortal_immovables_roots_;
178 }
179 
180 }  // namespace internal
181 }  // namespace v8
182