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