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/code-tracer.h"
9 #include "src/global-handles.h"
10 #include "src/objects-inl.h"
11 #include "src/v8threads.h"
12
13 namespace v8 {
14 namespace internal {
15
StartupSerializer(Isolate * isolate)16 StartupSerializer::StartupSerializer(Isolate* isolate)
17 : Serializer(isolate), can_be_rehashed_(true) {
18 InitializeCodeAddressMap();
19 }
20
~StartupSerializer()21 StartupSerializer::~StartupSerializer() {
22 RestoreExternalReferenceRedirectors(accessor_infos_);
23 RestoreExternalReferenceRedirectors(call_handler_infos_);
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(!ObjectIsBytecodeHandler(obj)); // Only referenced in dispatch table.
30 DCHECK(!obj->IsJSFunction());
31
32 if (SerializeBuiltinReference(obj, how_to_code, where_to_point, skip)) {
33 return;
34 }
35 if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
36
37 int root_index = root_index_map()->Lookup(obj);
38 // We can only encode roots as such if it has already been serialized.
39 // That applies to root indices below the wave front.
40 if (root_index != RootIndexMap::kInvalidRootIndex) {
41 if (root_has_been_serialized(root_index)) {
42 PutRoot(root_index, obj, how_to_code, where_to_point, skip);
43 return;
44 }
45 }
46
47 if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
48
49 FlushSkip(skip);
50 bool use_simulator = false;
51 #ifdef USE_SIMULATOR
52 use_simulator = true;
53 #endif
54
55 if (use_simulator && obj->IsAccessorInfo()) {
56 // Wipe external reference redirects in the accessor info.
57 AccessorInfo* info = AccessorInfo::cast(obj);
58 Address original_address = Foreign::cast(info->getter())->foreign_address();
59 Foreign::cast(info->js_getter())->set_foreign_address(original_address);
60 accessor_infos_.push_back(info);
61 } else if (use_simulator && obj->IsCallHandlerInfo()) {
62 CallHandlerInfo* info = CallHandlerInfo::cast(obj);
63 Address original_address =
64 Foreign::cast(info->callback())->foreign_address();
65 Foreign::cast(info->js_callback())->set_foreign_address(original_address);
66 call_handler_infos_.push_back(info);
67 } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) {
68 Script::cast(obj)->set_context_data(
69 ReadOnlyRoots(isolate()).uninitialized_symbol());
70 } else if (obj->IsSharedFunctionInfo()) {
71 // Clear inferred name for native functions.
72 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
73 if (!shared->IsSubjectToDebugging() && shared->HasUncompiledData()) {
74 shared->uncompiled_data()->set_inferred_name(
75 ReadOnlyRoots(isolate()).empty_string());
76 }
77 }
78
79 CheckRehashability(obj);
80
81 // Object has not yet been serialized. Serialize it here.
82 ObjectSerializer object_serializer(this, obj, &sink_, how_to_code,
83 where_to_point);
84 object_serializer.Serialize();
85 }
86
SerializeWeakReferencesAndDeferred()87 void StartupSerializer::SerializeWeakReferencesAndDeferred() {
88 // This comes right after serialization of the partial snapshot, where we
89 // add entries to the partial snapshot cache of the startup snapshot. Add
90 // one entry with 'undefined' to terminate the partial snapshot cache.
91 Object* undefined = ReadOnlyRoots(isolate()).undefined_value();
92 VisitRootPointer(Root::kPartialSnapshotCache, nullptr, &undefined);
93 isolate()->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
94 SerializeDeferredObjects();
95 Pad();
96 }
97
PartialSnapshotCacheIndex(HeapObject * heap_object)98 int StartupSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
99 int index;
100 if (!partial_cache_index_map_.LookupOrInsert(heap_object, &index)) {
101 // This object is not part of the partial snapshot cache yet. Add it to the
102 // startup snapshot so we can refer to it via partial snapshot index from
103 // the partial snapshot.
104 VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
105 reinterpret_cast<Object**>(&heap_object));
106 }
107 return index;
108 }
109
Synchronize(VisitorSynchronization::SyncTag tag)110 void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
111 sink_.Put(kSynchronize, "Synchronize");
112 }
113
SerializeStrongReferences()114 void StartupSerializer::SerializeStrongReferences() {
115 Isolate* isolate = this->isolate();
116 // No active threads.
117 CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
118 // No active or weak handles.
119 CHECK(isolate->handle_scope_implementer()->blocks()->empty());
120
121 // Visit smi roots.
122 // Clear the stack limits to make the snapshot reproducible.
123 // Reset it again afterwards.
124 isolate->heap()->ClearStackLimits();
125 isolate->heap()->IterateSmiRoots(this);
126 isolate->heap()->SetStackLimits();
127 // First visit immortal immovables to make sure they end up in the first page.
128 isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
129 }
130
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)131 void StartupSerializer::VisitRootPointers(Root root, const char* description,
132 Object** start, Object** end) {
133 if (start == isolate()->heap()->roots_array_start()) {
134 // Serializing the root list needs special handling:
135 // - Only root list elements that have been fully serialized can be
136 // referenced using kRootArray bytecodes.
137 for (Object** current = start; current < end; current++) {
138 SerializeRootObject(*current);
139 int root_index = static_cast<int>(current - start);
140 root_has_been_serialized_.set(root_index);
141 }
142 } else {
143 Serializer::VisitRootPointers(root, description, start, end);
144 }
145 }
146
CheckRehashability(HeapObject * obj)147 void StartupSerializer::CheckRehashability(HeapObject* obj) {
148 if (!can_be_rehashed_) return;
149 if (!obj->NeedsRehashing()) return;
150 if (obj->CanBeRehashed()) return;
151 can_be_rehashed_ = false;
152 }
153
MustBeDeferred(HeapObject * object)154 bool StartupSerializer::MustBeDeferred(HeapObject* object) {
155 if (root_has_been_serialized_.test(Heap::kFreeSpaceMapRootIndex) &&
156 root_has_been_serialized_.test(Heap::kOnePointerFillerMapRootIndex) &&
157 root_has_been_serialized_.test(Heap::kTwoPointerFillerMapRootIndex)) {
158 // All required root objects are serialized, so any aligned objects can
159 // be saved without problems.
160 return false;
161 }
162 // Just defer everything except of Map objects until all required roots are
163 // serialized. Some objects may have special alignment requirements, that may
164 // not be fulfilled during deserialization until few first root objects are
165 // serialized. But we must serialize Map objects since deserializer checks
166 // that these root objects are indeed Maps.
167 return !object->IsMap();
168 }
169
SerializedHandleChecker(Isolate * isolate,std::vector<Context * > * contexts)170 SerializedHandleChecker::SerializedHandleChecker(
171 Isolate* isolate, std::vector<Context*>* contexts)
172 : isolate_(isolate) {
173 AddToSet(isolate->heap()->serialized_objects());
174 for (auto const& context : *contexts) {
175 AddToSet(context->serialized_objects());
176 }
177 }
178
AddToSet(FixedArray * serialized)179 void SerializedHandleChecker::AddToSet(FixedArray* serialized) {
180 int length = serialized->length();
181 for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i));
182 }
183
VisitRootPointers(Root root,const char * description,Object ** start,Object ** end)184 void SerializedHandleChecker::VisitRootPointers(Root root,
185 const char* description,
186 Object** start, Object** end) {
187 for (Object** p = start; p < end; p++) {
188 if (serialized_.find(*p) != serialized_.end()) continue;
189 PrintF("%s handle not serialized: ",
190 root == Root::kGlobalHandles ? "global" : "eternal");
191 (*p)->Print();
192 ok_ = false;
193 }
194 }
195
CheckGlobalAndEternalHandles()196 bool SerializedHandleChecker::CheckGlobalAndEternalHandles() {
197 isolate_->global_handles()->IterateAllRoots(this);
198 isolate_->eternal_handles()->IterateAllRoots(this);
199 return ok_;
200 }
201
202 } // namespace internal
203 } // namespace v8
204