Line data Source code
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.h"
8 : #include "src/objects-inl.h"
9 : #include "src/v8threads.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 161 : StartupSerializer::StartupSerializer(
15 : Isolate* isolate,
16 : v8::SnapshotCreator::FunctionCodeHandling function_code_handling)
17 : : Serializer(isolate),
18 161 : clear_function_code_(function_code_handling ==
19 : v8::SnapshotCreator::FunctionCodeHandling::kClear),
20 483 : can_be_rehashed_(true) {
21 161 : InitializeCodeAddressMap();
22 161 : }
23 :
24 161 : StartupSerializer::~StartupSerializer() {
25 161 : RestoreExternalReferenceRedirectors(accessor_infos_);
26 161 : OutputStatistics("StartupSerializer");
27 161 : }
28 :
29 4358756 : void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
30 8717512 : WhereToPoint where_to_point, int skip) {
31 : DCHECK(!obj->IsJSFunction());
32 :
33 8351937 : if (clear_function_code() && obj->IsBytecodeArray()) {
34 893303 : obj = isolate()->heap()->undefined_value();
35 : }
36 :
37 : BuiltinReferenceSerializationMode mode =
38 4358756 : clear_function_code() ? kCanonicalizeCompileLazy : kDefault;
39 4358756 : if (SerializeBuiltinReference(obj, how_to_code, where_to_point, skip, mode)) {
40 3496037 : return;
41 : }
42 3944887 : if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
43 :
44 3529520 : int root_index = root_index_map()->Lookup(obj);
45 : // We can only encode roots as such if it has already been serialized.
46 : // That applies to root indices below the wave front.
47 3529520 : if (root_index != RootIndexMap::kInvalidRootIndex) {
48 2262453 : if (root_has_been_serialized(root_index)) {
49 2186357 : PutRoot(root_index, obj, how_to_code, where_to_point, skip);
50 2186357 : return;
51 : }
52 : }
53 :
54 1343163 : if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
55 :
56 862719 : FlushSkip(skip);
57 :
58 862719 : if (isolate()->external_reference_redirector() && obj->IsAccessorInfo()) {
59 : // Wipe external reference redirects in the accessor info.
60 0 : AccessorInfo* info = AccessorInfo::cast(obj);
61 : Address original_address = Foreign::cast(info->getter())->foreign_address();
62 : Foreign::cast(info->js_getter())->set_foreign_address(original_address);
63 0 : accessor_infos_.push_back(info);
64 862719 : } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) {
65 : Script::cast(obj)->set_context_data(
66 60 : isolate()->heap()->uninitialized_symbol());
67 862659 : } else if (obj->IsSharedFunctionInfo()) {
68 : // Clear inferred name for native functions.
69 : SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
70 150620 : if (!shared->IsSubjectToDebugging() && shared->HasInferredName()) {
71 29737 : shared->set_inferred_name(isolate()->heap()->empty_string());
72 : }
73 : }
74 :
75 862719 : if (obj->IsHashTable()) CheckRehashability(obj);
76 :
77 : // Object has not yet been serialized. Serialize it here.
78 : ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
79 862719 : where_to_point);
80 862719 : object_serializer.Serialize();
81 : }
82 :
83 161 : void StartupSerializer::SerializeWeakReferencesAndDeferred() {
84 : // This comes right after serialization of the partial snapshot, where we
85 : // add entries to the partial snapshot cache of the startup snapshot. Add
86 : // one entry with 'undefined' to terminate the partial snapshot cache.
87 322 : Object* undefined = isolate()->heap()->undefined_value();
88 161 : VisitRootPointer(Root::kPartialSnapshotCache, &undefined);
89 161 : isolate()->heap()->IterateWeakRoots(this, VISIT_ALL);
90 161 : SerializeDeferredObjects();
91 161 : Pad();
92 161 : }
93 :
94 791196 : int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
95 : int index;
96 791196 : if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
97 : // This object is not part of the partial snapshot cache yet. Add it to the
98 : // startup snapshot so we can refer to it via partial snapshot index from
99 : // the partial snapshot.
100 : VisitRootPointer(Root::kPartialSnapshotCache,
101 362513 : reinterpret_cast<Object**>(&heap_object));
102 : }
103 791196 : return index;
104 : }
105 :
106 2898 : void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
107 : sink_.Put(kSynchronize, "Synchronize");
108 2898 : }
109 :
110 161 : void StartupSerializer::SerializeStrongReferences() {
111 644 : Isolate* isolate = this->isolate();
112 : // No active threads.
113 161 : CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
114 : // No active or weak handles.
115 161 : CHECK(isolate->handle_scope_implementer()->blocks()->empty());
116 161 : CHECK_EQ(0, isolate->global_handles()->global_handles_count());
117 161 : CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles());
118 : // First visit immortal immovables to make sure they end up in the first page.
119 161 : serializing_immortal_immovables_roots_ = true;
120 161 : isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
121 : // Check that immortal immovable roots are allocated on the first page.
122 : DCHECK(allocator()->HasNotExceededFirstPageOfEachSpace());
123 161 : serializing_immortal_immovables_roots_ = false;
124 : // Visit the rest of the strong roots.
125 : // Clear the stack limits to make the snapshot reproducible.
126 : // Reset it again afterwards.
127 161 : isolate->heap()->ClearStackLimits();
128 161 : isolate->heap()->IterateSmiRoots(this);
129 161 : isolate->heap()->SetStackLimits();
130 :
131 : isolate->heap()->IterateStrongRoots(this,
132 161 : VISIT_ONLY_STRONG_FOR_SERIALIZATION);
133 161 : }
134 :
135 489351 : void StartupSerializer::VisitRootPointers(Root root, Object** start,
136 : Object** end) {
137 489351 : if (start == isolate()->heap()->roots_array_start()) {
138 : // Serializing the root list needs special handling:
139 : // - The first pass over the root list only serializes immortal immovables.
140 : // - The second pass over the root list serializes the rest.
141 : // - Only root list elements that have been fully serialized can be
142 : // referenced via as root by using kRootArray bytecodes.
143 : int skip = 0;
144 138782 : for (Object** current = start; current < end; current++) {
145 138782 : int root_index = static_cast<int>(current - start);
146 138782 : if (RootShouldBeSkipped(root_index)) {
147 69391 : skip += kPointerSize;
148 69391 : continue;
149 : } else {
150 138782 : if ((*current)->IsSmi()) {
151 161 : FlushSkip(skip);
152 161 : PutSmi(Smi::cast(*current));
153 : } else {
154 : SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject,
155 69230 : skip);
156 : }
157 69391 : root_has_been_serialized_.set(root_index);
158 : skip = 0;
159 : }
160 : }
161 322 : FlushSkip(skip);
162 : } else {
163 489029 : Serializer::VisitRootPointers(root, start, end);
164 : }
165 489351 : }
166 :
167 0 : bool StartupSerializer::RootShouldBeSkipped(int root_index) {
168 138782 : if (root_index == Heap::kStackLimitRootIndex ||
169 : root_index == Heap::kRealStackLimitRootIndex) {
170 : return true;
171 : }
172 138782 : return Heap::RootIsImmortalImmovable(root_index) !=
173 138782 : serializing_immortal_immovables_roots_;
174 : }
175 :
176 971 : void StartupSerializer::CheckRehashability(HeapObject* table) {
177 : DCHECK(table->IsHashTable());
178 971 : if (!can_be_rehashed_) return;
179 : // We can only correctly rehash if the four hash tables below are the only
180 : // ones that we deserialize.
181 956 : if (table->IsUnseededNumberDictionary()) return;
182 800 : if (table == isolate()->heap()->empty_ordered_hash_table()) return;
183 639 : if (table == isolate()->heap()->empty_slow_element_dictionary()) return;
184 478 : if (table == isolate()->heap()->empty_property_dictionary()) return;
185 317 : if (table == isolate()->heap()->weak_object_to_code_table()) return;
186 161 : if (table == isolate()->heap()->string_table()) return;
187 5 : can_be_rehashed_ = false;
188 : }
189 :
190 862714 : bool StartupSerializer::MustBeDeferred(HeapObject* object) {
191 2587015 : if (root_has_been_serialized_.test(Heap::kFreeSpaceMapRootIndex) &&
192 1724140 : root_has_been_serialized_.test(Heap::kOnePointerFillerMapRootIndex) &&
193 861426 : root_has_been_serialized_.test(Heap::kTwoPointerFillerMapRootIndex)) {
194 : // All required root objects are serialized, so any aligned objects can
195 : // be saved without problems.
196 : return false;
197 : }
198 : // Just defer everything except of Map objects until all required roots are
199 : // serialized. Some objects may have special alignment requirements, that may
200 : // not be fulfilled during deserialization until few first root objects are
201 : // serialized. But we must serialize Map objects since deserializer checks
202 : // that these root objects are indeed Maps.
203 1449 : return !object->IsMap();
204 : }
205 :
206 : } // namespace internal
207 : } // namespace v8
|