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/code-tracer.h"
9 : #include "src/contexts.h"
10 : #include "src/deoptimizer.h"
11 : #include "src/global-handles.h"
12 : #include "src/heap/heap-inl.h"
13 : #include "src/objects-inl.h"
14 : #include "src/objects/foreign-inl.h"
15 : #include "src/objects/slots.h"
16 : #include "src/snapshot/read-only-serializer.h"
17 : #include "src/v8threads.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 256 : StartupSerializer::StartupSerializer(Isolate* isolate,
23 : ReadOnlySerializer* read_only_serializer)
24 : : RootsSerializer(isolate, RootIndex::kFirstStrongRoot),
25 256 : read_only_serializer_(read_only_serializer) {
26 256 : InitializeCodeAddressMap();
27 256 : }
28 :
29 256 : StartupSerializer::~StartupSerializer() {
30 256 : RestoreExternalReferenceRedirectors(accessor_infos_);
31 256 : RestoreExternalReferenceRedirectors(call_handler_infos_);
32 256 : OutputStatistics("StartupSerializer");
33 256 : }
34 :
35 : #ifdef DEBUG
36 : namespace {
37 :
38 : bool IsUnexpectedCodeObject(Isolate* isolate, HeapObject obj) {
39 : if (!obj->IsCode()) return false;
40 :
41 : Code code = Code::cast(obj);
42 :
43 : // TODO(v8:8768): Deopt entry code should not be serialized.
44 : if (code->kind() == Code::STUB && isolate->deoptimizer_data() != nullptr) {
45 : if (isolate->deoptimizer_data()->IsDeoptEntryCode(code)) return false;
46 : }
47 :
48 : if (code->kind() == Code::REGEXP) return false;
49 : if (!code->is_builtin()) return true;
50 : if (!FLAG_embedded_builtins) return false;
51 : if (code->is_off_heap_trampoline()) return false;
52 :
53 : // An on-heap builtin. We only expect this for the interpreter entry
54 : // trampoline copy stored on the root list and transitively called builtins.
55 : // See Heap::interpreter_entry_trampoline_for_profiling.
56 :
57 : switch (code->builtin_index()) {
58 : case Builtins::kAbort:
59 : case Builtins::kCEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
60 : case Builtins::kInterpreterEntryTrampoline:
61 : case Builtins::kRecordWrite:
62 : return false;
63 : default:
64 : return true;
65 : }
66 :
67 : UNREACHABLE();
68 : }
69 :
70 : } // namespace
71 : #endif // DEBUG
72 :
73 5046630 : void StartupSerializer::SerializeObject(HeapObject obj) {
74 : DCHECK(!obj->IsJSFunction());
75 : DCHECK(!IsUnexpectedCodeObject(isolate(), obj));
76 :
77 8973318 : if (SerializeHotObject(obj)) return;
78 3649560 : if (IsRootAndHasBeenSerialized(obj) && SerializeRoot(obj)) return;
79 3316680 : if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
80 1546928 : if (SerializeBackReference(obj)) return;
81 :
82 : bool use_simulator = false;
83 : #ifdef USE_SIMULATOR
84 : use_simulator = true;
85 : #endif
86 :
87 : if (use_simulator && obj->IsAccessorInfo()) {
88 : // Wipe external reference redirects in the accessor info.
89 : AccessorInfo info = AccessorInfo::cast(obj);
90 : Address original_address = Foreign::cast(info->getter())->foreign_address();
91 : Foreign::cast(info->js_getter())->set_foreign_address(original_address);
92 : accessor_infos_.push_back(info);
93 : } else if (use_simulator && obj->IsCallHandlerInfo()) {
94 : CallHandlerInfo info = CallHandlerInfo::cast(obj);
95 : Address original_address =
96 : Foreign::cast(info->callback())->foreign_address();
97 : Foreign::cast(info->js_callback())->set_foreign_address(original_address);
98 : call_handler_infos_.push_back(info);
99 1122639 : } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) {
100 : Script::cast(obj)->set_context_data(
101 230 : ReadOnlyRoots(isolate()).uninitialized_symbol());
102 1121751 : } else if (obj->IsSharedFunctionInfo()) {
103 : // Clear inferred name for native functions.
104 175481 : SharedFunctionInfo shared = SharedFunctionInfo::cast(obj);
105 175481 : if (!shared->IsSubjectToDebugging() && shared->HasUncompiledData()) {
106 : shared->uncompiled_data()->set_inferred_name(
107 1809 : ReadOnlyRoots(isolate()).empty_string());
108 : }
109 : }
110 :
111 1121866 : CheckRehashability(obj);
112 :
113 : // Object has not yet been serialized. Serialize it here.
114 : DCHECK(!isolate()->heap()->InReadOnlySpace(obj));
115 : ObjectSerializer object_serializer(this, obj, &sink_);
116 1121866 : object_serializer.Serialize();
117 : }
118 :
119 256 : void StartupSerializer::SerializeWeakReferencesAndDeferred() {
120 : // This comes right after serialization of the partial snapshot, where we
121 : // add entries to the partial snapshot cache of the startup snapshot. Add
122 : // one entry with 'undefined' to terminate the partial snapshot cache.
123 768 : Object undefined = ReadOnlyRoots(isolate()).undefined_value();
124 : VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
125 512 : FullObjectSlot(&undefined));
126 256 : isolate()->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION);
127 256 : SerializeDeferredObjects();
128 256 : Pad();
129 256 : }
130 :
131 256 : void StartupSerializer::SerializeStrongReferences() {
132 512 : Isolate* isolate = this->isolate();
133 : // No active threads.
134 256 : CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
135 : // No active or weak handles.
136 256 : CHECK(isolate->handle_scope_implementer()->blocks()->empty());
137 :
138 : // Visit smi roots.
139 : // Clear the stack limits to make the snapshot reproducible.
140 : // Reset it again afterwards.
141 256 : isolate->heap()->ClearStackLimits();
142 256 : isolate->heap()->IterateSmiRoots(this);
143 256 : isolate->heap()->SetStackLimits();
144 : // First visit immortal immovables to make sure they end up in the first page.
145 256 : isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION);
146 256 : }
147 :
148 191 : SerializedHandleChecker::SerializedHandleChecker(Isolate* isolate,
149 : std::vector<Context>* contexts)
150 382 : : isolate_(isolate) {
151 191 : AddToSet(isolate->heap()->serialized_objects());
152 608 : for (auto const& context : *contexts) {
153 226 : AddToSet(context->serialized_objects());
154 : }
155 191 : }
156 :
157 1037355 : bool StartupSerializer::SerializeUsingReadOnlyObjectCache(
158 : SnapshotByteSink* sink, HeapObject obj) {
159 2695695 : return read_only_serializer_->SerializeUsingReadOnlyObjectCache(sink, obj);
160 : }
161 :
162 498698 : void StartupSerializer::SerializeUsingPartialSnapshotCache(
163 : SnapshotByteSink* sink, HeapObject obj) {
164 498698 : int cache_index = SerializeInObjectCache(obj);
165 : sink->Put(kPartialSnapshotCache, "PartialSnapshotCache");
166 498698 : sink->PutInt(cache_index, "partial_snapshot_cache_index");
167 498698 : }
168 :
169 417 : void SerializedHandleChecker::AddToSet(FixedArray serialized) {
170 : int length = serialized->length();
171 587 : for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i));
172 417 : }
173 :
174 20 : void SerializedHandleChecker::VisitRootPointers(Root root,
175 : const char* description,
176 : FullObjectSlot start,
177 : FullObjectSlot end) {
178 60 : for (FullObjectSlot p = start; p < end; ++p) {
179 40 : if (serialized_.find(*p) != serialized_.end()) continue;
180 : PrintF("%s handle not serialized: ",
181 0 : root == Root::kGlobalHandles ? "global" : "eternal");
182 0 : (*p)->Print();
183 0 : ok_ = false;
184 : }
185 20 : }
186 :
187 191 : bool SerializedHandleChecker::CheckGlobalAndEternalHandles() {
188 382 : isolate_->global_handles()->IterateAllRoots(this);
189 382 : isolate_->eternal_handles()->IterateAllRoots(this);
190 191 : return ok_;
191 : }
192 :
193 : } // namespace internal
194 178779 : } // namespace v8
|