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/objects-inl.h"
10
11 namespace v8 {
12 namespace internal {
13
PartialSerializer(Isolate * isolate,StartupSerializer * startup_serializer,v8::SerializeEmbedderFieldsCallback callback)14 PartialSerializer::PartialSerializer(
15 Isolate* isolate, StartupSerializer* startup_serializer,
16 v8::SerializeEmbedderFieldsCallback callback)
17 : Serializer(isolate),
18 startup_serializer_(startup_serializer),
19 serialize_embedder_fields_(callback),
20 can_be_rehashed_(true),
21 context_(nullptr) {
22 InitializeCodeAddressMap();
23 allocator()->UseCustomChunkSize(FLAG_serialization_chunk_size);
24 }
25
~PartialSerializer()26 PartialSerializer::~PartialSerializer() {
27 OutputStatistics("PartialSerializer");
28 }
29
Serialize(Context ** o,bool include_global_proxy)30 void PartialSerializer::Serialize(Context** o, bool include_global_proxy) {
31 context_ = *o;
32 DCHECK(context_->IsNativeContext());
33 reference_map()->AddAttachedReference(context_->global_proxy());
34 // The bootstrap snapshot has a code-stub context. When serializing the
35 // partial snapshot, it is chained into the weak context list on the isolate
36 // and it's next context pointer may point to the code-stub context. Clear
37 // it before serializing, it will get re-added to the context list
38 // explicitly when it's loaded.
39 context_->set(Context::NEXT_CONTEXT_LINK,
40 ReadOnlyRoots(isolate()).undefined_value());
41 DCHECK(!context_->global_object()->IsUndefined());
42 // Reset math random cache to get fresh random numbers.
43 context_->set_math_random_index(Smi::kZero);
44 context_->set_math_random_cache(ReadOnlyRoots(isolate()).undefined_value());
45
46 VisitRootPointer(Root::kPartialSnapshotCache, nullptr,
47 reinterpret_cast<Object**>(o));
48 SerializeDeferredObjects();
49 SerializeEmbedderFields();
50 Pad();
51 }
52
SerializeObject(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)53 void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
54 WhereToPoint where_to_point, int skip) {
55 DCHECK(!ObjectIsBytecodeHandler(obj)); // Only referenced in dispatch table.
56
57 if (SerializeBuiltinReference(obj, how_to_code, where_to_point, skip)) {
58 return;
59 }
60 if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
61
62 int root_index = root_index_map()->Lookup(obj);
63 if (root_index != RootIndexMap::kInvalidRootIndex) {
64 PutRoot(root_index, obj, how_to_code, where_to_point, skip);
65 return;
66 }
67
68 if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
69
70 if (ShouldBeInThePartialSnapshotCache(obj)) {
71 FlushSkip(skip);
72
73 int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
74 sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
75 "PartialSnapshotCache");
76 sink_.PutInt(cache_index, "partial_snapshot_cache_index");
77 return;
78 }
79
80 // Pointers from the partial snapshot to the objects in the startup snapshot
81 // should go through the root array or through the partial snapshot cache.
82 // If this is not the case you may have to add something to the root array.
83 DCHECK(!startup_serializer_->ReferenceMapContains(obj));
84 // All the internalized strings that the partial snapshot needs should be
85 // either in the root table or in the partial snapshot cache.
86 DCHECK(!obj->IsInternalizedString());
87 // Function and object templates are not context specific.
88 DCHECK(!obj->IsTemplateInfo());
89 // We should not end up at another native context.
90 DCHECK_IMPLIES(obj != context_, !obj->IsNativeContext());
91
92 FlushSkip(skip);
93
94 // Clear literal boilerplates and feedback.
95 if (obj->IsFeedbackVector()) FeedbackVector::cast(obj)->ClearSlots(isolate());
96
97 if (obj->IsJSObject()) {
98 JSObject* jsobj = JSObject::cast(obj);
99 if (jsobj->GetEmbedderFieldCount() > 0) {
100 DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
101 embedder_field_holders_.push_back(jsobj);
102 }
103 }
104
105 if (obj->IsJSFunction()) {
106 // Unconditionally reset the JSFunction to its SFI's code, since we can't
107 // serialize optimized code anyway.
108 JSFunction* closure = JSFunction::cast(obj);
109 if (closure->is_compiled()) closure->set_code(closure->shared()->GetCode());
110 }
111
112 CheckRehashability(obj);
113
114 // Object has not yet been serialized. Serialize it here.
115 ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
116 serializer.Serialize();
117 }
118
ShouldBeInThePartialSnapshotCache(HeapObject * o)119 bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
120 // Scripts should be referred only through shared function infos. We can't
121 // allow them to be part of the partial snapshot because they contain a
122 // unique ID, and deserializing several partial snapshots containing script
123 // would cause dupes.
124 DCHECK(!o->IsScript());
125 return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
126 o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
127 o->IsTemplateInfo() ||
128 o->map() == ReadOnlyRoots(startup_serializer_->isolate())
129 .fixed_cow_array_map();
130 }
131
SerializeEmbedderFields()132 void PartialSerializer::SerializeEmbedderFields() {
133 if (embedder_field_holders_.empty()) return;
134 DisallowHeapAllocation no_gc;
135 DisallowJavascriptExecution no_js(isolate());
136 DisallowCompilation no_compile(isolate());
137 DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
138 sink_.Put(kEmbedderFieldsData, "embedder fields data");
139 while (!embedder_field_holders_.empty()) {
140 HandleScope scope(isolate());
141 Handle<JSObject> obj(embedder_field_holders_.back(), isolate());
142 embedder_field_holders_.pop_back();
143 SerializerReference reference = reference_map()->LookupReference(*obj);
144 DCHECK(reference.is_back_reference());
145 int embedder_fields_count = obj->GetEmbedderFieldCount();
146 for (int i = 0; i < embedder_fields_count; i++) {
147 if (obj->GetEmbedderField(i)->IsHeapObject()) continue;
148
149 StartupData data = serialize_embedder_fields_.callback(
150 v8::Utils::ToLocal(obj), i, serialize_embedder_fields_.data);
151 sink_.Put(kNewObject + reference.space(), "embedder field holder");
152 PutBackReference(*obj, reference);
153 sink_.PutInt(i, "embedder field index");
154 sink_.PutInt(data.raw_size, "embedder fields data size");
155 sink_.PutRaw(reinterpret_cast<const byte*>(data.data), data.raw_size,
156 "embedder fields data");
157 delete[] data.data;
158 }
159 }
160 sink_.Put(kSynchronize, "Finished with embedder fields data");
161 }
162
CheckRehashability(HeapObject * obj)163 void PartialSerializer::CheckRehashability(HeapObject* obj) {
164 if (!can_be_rehashed_) return;
165 if (!obj->NeedsRehashing()) return;
166 if (obj->CanBeRehashed()) return;
167 can_be_rehashed_ = false;
168 }
169
170 } // namespace internal
171 } // namespace v8
172