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/partial-serializer.h"
6 : #include "src/snapshot/startup-serializer.h"
7 :
8 : #include "src/api-inl.h"
9 : #include "src/math-random.h"
10 : #include "src/microtask-queue.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/slots.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 236 : PartialSerializer::PartialSerializer(
18 : Isolate* isolate, StartupSerializer* startup_serializer,
19 : v8::SerializeEmbedderFieldsCallback callback)
20 : : Serializer(isolate),
21 : startup_serializer_(startup_serializer),
22 : serialize_embedder_fields_(callback),
23 236 : can_be_rehashed_(true) {
24 236 : InitializeCodeAddressMap();
25 236 : allocator()->UseCustomChunkSize(FLAG_serialization_chunk_size);
26 236 : }
27 :
28 472 : PartialSerializer::~PartialSerializer() {
29 236 : OutputStatistics("PartialSerializer");
30 236 : }
31 :
32 236 : void PartialSerializer::Serialize(Context* o, bool include_global_proxy) {
33 236 : context_ = *o;
34 : DCHECK(context_->IsNativeContext());
35 : reference_map()->AddAttachedReference(
36 472 : reinterpret_cast<void*>(context_->global_proxy()->ptr()));
37 : // The bootstrap snapshot has a code-stub context. When serializing the
38 : // partial snapshot, it is chained into the weak context list on the isolate
39 : // and it's next context pointer may point to the code-stub context. Clear
40 : // it before serializing, it will get re-added to the context list
41 : // explicitly when it's loaded.
42 : context_->set(Context::NEXT_CONTEXT_LINK,
43 : ReadOnlyRoots(isolate()).undefined_value());
44 : DCHECK(!context_->global_object()->IsUndefined());
45 : // Reset math random cache to get fresh random numbers.
46 236 : MathRandom::ResetContext(context_);
47 :
48 : #ifdef DEBUG
49 : MicrotaskQueue* microtask_queue =
50 : context_->native_context()->microtask_queue();
51 : DCHECK_EQ(0, microtask_queue->size());
52 : DCHECK(!microtask_queue->HasMicrotasksSuppressions());
53 : DCHECK_EQ(0, microtask_queue->GetMicrotasksScopeDepth());
54 : DCHECK(microtask_queue->DebugMicrotasksScopeDepthIsZero());
55 : #endif
56 472 : context_->native_context()->set_microtask_queue(nullptr);
57 :
58 472 : VisitRootPointer(Root::kPartialSnapshotCache, nullptr, FullObjectSlot(o));
59 236 : SerializeDeferredObjects();
60 :
61 : // Add section for embedder-serialized embedder fields.
62 236 : if (!embedder_fields_sink_.data()->empty()) {
63 : sink_.Put(kEmbedderFieldsData, "embedder fields data");
64 5 : sink_.Append(embedder_fields_sink_);
65 : sink_.Put(kSynchronize, "Finished with embedder fields data");
66 : }
67 :
68 236 : Pad();
69 236 : }
70 :
71 3007665 : void PartialSerializer::SerializeObject(HeapObject obj) {
72 : DCHECK(!ObjectIsBytecodeHandler(obj)); // Only referenced in dispatch table.
73 :
74 5478776 : if (SerializeHotObject(obj)) return;
75 :
76 2392565 : if (SerializeRoot(obj)) return;
77 :
78 1271061 : if (SerializeBackReference(obj)) return;
79 :
80 1037355 : if (startup_serializer_->SerializeUsingReadOnlyObjectCache(&sink_, obj)) {
81 : return;
82 : }
83 :
84 1035432 : if (ShouldBeInThePartialSnapshotCache(obj)) {
85 498698 : startup_serializer_->SerializeUsingPartialSnapshotCache(&sink_, obj);
86 498698 : return;
87 : }
88 :
89 : // Pointers from the partial snapshot to the objects in the startup snapshot
90 : // should go through the root array or through the partial snapshot cache.
91 : // If this is not the case you may have to add something to the root array.
92 : DCHECK(!startup_serializer_->ReferenceMapContains(obj));
93 : // All the internalized strings that the partial snapshot needs should be
94 : // either in the root table or in the partial snapshot cache.
95 : DCHECK(!obj->IsInternalizedString());
96 : // Function and object templates are not context specific.
97 : DCHECK(!obj->IsTemplateInfo());
98 : // We should not end up at another native context.
99 : DCHECK_IMPLIES(obj != context_, !obj->IsNativeContext());
100 :
101 : // Clear literal boilerplates and feedback.
102 536749 : if (obj->IsFeedbackVector()) FeedbackVector::cast(obj)->ClearSlots(isolate());
103 :
104 536734 : if (SerializeJSObjectWithEmbedderFields(obj)) {
105 : return;
106 : }
107 :
108 536569 : if (obj->IsJSFunction()) {
109 : // Unconditionally reset the JSFunction to its SFI's code, since we can't
110 : // serialize optimized code anyway.
111 192568 : JSFunction closure = JSFunction::cast(obj);
112 192568 : closure->ResetIfBytecodeFlushed();
113 192568 : if (closure->is_compiled()) closure->set_code(closure->shared()->GetCode());
114 : }
115 :
116 536569 : CheckRehashability(obj);
117 :
118 : // Object has not yet been serialized. Serialize it here.
119 : ObjectSerializer serializer(this, obj, &sink_);
120 536569 : serializer.Serialize();
121 : }
122 :
123 1035432 : bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject o) {
124 : // Scripts should be referred only through shared function infos. We can't
125 : // allow them to be part of the partial snapshot because they contain a
126 : // unique ID, and deserializing several partial snapshots containing script
127 : // would cause dupes.
128 : DCHECK(!o->IsScript());
129 2387118 : return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
130 1611065 : o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
131 2108920 : o->IsTemplateInfo() || o->IsClassPositions() ||
132 : o->map() == ReadOnlyRoots(startup_serializer_->isolate())
133 1572171 : .fixed_cow_array_map();
134 : }
135 :
136 : namespace {
137 : bool DataIsEmpty(const StartupData& data) { return data.raw_size == 0; }
138 : } // anonymous namespace
139 :
140 536734 : bool PartialSerializer::SerializeJSObjectWithEmbedderFields(Object obj) {
141 536734 : if (!obj->IsJSObject()) return false;
142 262074 : JSObject js_obj = JSObject::cast(obj);
143 262074 : int embedder_fields_count = js_obj->GetEmbedderFieldCount();
144 262074 : if (embedder_fields_count == 0) return false;
145 165 : CHECK_GT(embedder_fields_count, 0);
146 : DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
147 : DCHECK(!js_obj->NeedsRehashing());
148 :
149 : DisallowHeapAllocation no_gc;
150 330 : DisallowJavascriptExecution no_js(isolate());
151 : DisallowCompilation no_compile(isolate());
152 :
153 : HandleScope scope(isolate());
154 : Handle<JSObject> obj_handle(js_obj, isolate());
155 165 : v8::Local<v8::Object> api_obj = v8::Utils::ToLocal(obj_handle);
156 :
157 : std::vector<EmbedderDataSlot::RawData> original_embedder_values;
158 : std::vector<StartupData> serialized_data;
159 :
160 : // 1) Iterate embedder fields. Hold onto the original value of the fields.
161 : // Ignore references to heap objects since these are to be handled by the
162 : // serializer. For aligned pointers, call the serialize callback. Hold
163 : // onto the result.
164 525 : for (int i = 0; i < embedder_fields_count; i++) {
165 : EmbedderDataSlot embedder_data_slot(js_obj, i);
166 360 : original_embedder_values.emplace_back(embedder_data_slot.load_raw(no_gc));
167 360 : Object object = embedder_data_slot.load_tagged();
168 360 : if (object->IsHeapObject()) {
169 : DCHECK(isolate()->heap()->Contains(HeapObject::cast(object)));
170 220 : serialized_data.push_back({nullptr, 0});
171 : } else {
172 : StartupData data = serialize_embedder_fields_.callback(
173 250 : api_obj, i, serialize_embedder_fields_.data);
174 250 : serialized_data.push_back(data);
175 : }
176 : }
177 :
178 : // 2) Embedder fields for which the embedder callback produced non-zero
179 : // serialized data should be considered aligned pointers to objects owned
180 : // by the embedder. Clear these memory addresses to avoid non-determism
181 : // in the snapshot. This is done separately to step 1 to no not interleave
182 : // with embedder callbacks.
183 360 : for (int i = 0; i < embedder_fields_count; i++) {
184 720 : if (!DataIsEmpty(serialized_data[i])) {
185 15 : EmbedderDataSlot(js_obj, i).store_raw({kNullAddress}, no_gc);
186 : }
187 : }
188 :
189 : // 3) Serialize the object. References from embedder fields to heap objects or
190 : // smis are serialized regularly.
191 495 : ObjectSerializer(this, js_obj, &sink_).Serialize();
192 :
193 : // 4) Obtain back reference for the serialized object.
194 : SerializerReference reference =
195 165 : reference_map()->LookupReference(reinterpret_cast<void*>(js_obj->ptr()));
196 : DCHECK(reference.is_back_reference());
197 :
198 : // 5) Write data returned by the embedder callbacks into a separate sink,
199 : // headed by the back reference. Restore the original embedder fields.
200 525 : for (int i = 0; i < embedder_fields_count; i++) {
201 720 : StartupData data = serialized_data[i];
202 360 : if (DataIsEmpty(data)) continue;
203 : // Restore original values from cleared fields.
204 30 : EmbedderDataSlot(js_obj, i).store_raw(original_embedder_values[i], no_gc);
205 : embedder_fields_sink_.Put(kNewObject + reference.space(),
206 : "embedder field holder");
207 15 : embedder_fields_sink_.PutInt(reference.chunk_index(), "BackRefChunkIndex");
208 15 : embedder_fields_sink_.PutInt(reference.chunk_offset(),
209 15 : "BackRefChunkOffset");
210 15 : embedder_fields_sink_.PutInt(i, "embedder field index");
211 15 : embedder_fields_sink_.PutInt(data.raw_size, "embedder fields data size");
212 : embedder_fields_sink_.PutRaw(reinterpret_cast<const byte*>(data.data),
213 15 : data.raw_size, "embedder fields data");
214 15 : delete[] data.data;
215 : }
216 :
217 : // 6) The content of the separate sink is appended eventually to the default
218 : // sink. The ensures that during deserialization, we call the deserializer
219 : // callback at the end, and can guarantee that the deserialized objects are
220 : // in a consistent state. See PartialSerializer::Serialize.
221 165 : return true;
222 : }
223 :
224 536569 : void PartialSerializer::CheckRehashability(HeapObject obj) {
225 536569 : if (!can_be_rehashed_) return;
226 531984 : if (!obj->NeedsRehashing()) return;
227 36542 : if (obj->CanBeRehashed()) return;
228 5 : can_be_rehashed_ = false;
229 : }
230 :
231 : } // namespace internal
232 178779 : } // namespace v8
|