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.h"
9 : #include "src/objects-inl.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 151 : 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 : rehashable_global_dictionary_(nullptr),
21 302 : can_be_rehashed_(true) {
22 151 : InitializeCodeAddressMap();
23 151 : }
24 :
25 302 : PartialSerializer::~PartialSerializer() {
26 151 : OutputStatistics("PartialSerializer");
27 151 : }
28 :
29 151 : void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
30 : DCHECK((*o)->IsNativeContext());
31 :
32 151 : Context* context = Context::cast(*o);
33 302 : 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 151 : isolate()->heap()->undefined_value());
41 : DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
42 : // Reset math random cache to get fresh random numbers.
43 : context->set_math_random_index(Smi::kZero);
44 151 : context->set_math_random_cache(isolate()->heap()->undefined_value());
45 : DCHECK_NULL(rehashable_global_dictionary_);
46 302 : rehashable_global_dictionary_ = context->global_object()->global_dictionary();
47 :
48 151 : VisitRootPointer(Root::kPartialSnapshotCache, o);
49 151 : SerializeDeferredObjects();
50 151 : SerializeEmbedderFields();
51 151 : Pad();
52 151 : }
53 :
54 2618614 : void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
55 : WhereToPoint where_to_point, int skip) {
56 : BuiltinReferenceSerializationMode mode =
57 2618614 : startup_serializer_->clear_function_code() ? kCanonicalizeCompileLazy
58 2618614 : : kDefault;
59 2628161 : if (SerializeBuiltinReference(obj, how_to_code, where_to_point, skip, mode)) {
60 2133277 : return;
61 : }
62 2457736 : if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
63 :
64 1827383 : int root_index = root_index_map()->Lookup(obj);
65 1827383 : if (root_index != RootIndexMap::kInvalidRootIndex) {
66 832993 : PutRoot(root_index, obj, how_to_code, where_to_point, skip);
67 832993 : return;
68 : }
69 :
70 994390 : if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
71 :
72 773247 : if (ShouldBeInThePartialSnapshotCache(obj)) {
73 287910 : FlushSkip(skip);
74 :
75 287910 : int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
76 : sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
77 287910 : "PartialSnapshotCache");
78 287910 : sink_.PutInt(cache_index, "partial_snapshot_cache_index");
79 287910 : return;
80 : }
81 :
82 : // Pointers from the partial snapshot to the objects in the startup snapshot
83 : // should go through the root array or through the partial snapshot cache.
84 : // If this is not the case you may have to add something to the root array.
85 : DCHECK(!startup_serializer_->ReferenceMapContains(obj));
86 : // All the internalized strings that the partial snapshot needs should be
87 : // either in the root table or in the partial snapshot cache.
88 : DCHECK(!obj->IsInternalizedString());
89 : // Function and object templates are not context specific.
90 : DCHECK(!obj->IsTemplateInfo());
91 :
92 485337 : FlushSkip(skip);
93 :
94 : // Clear literal boilerplates and feedback.
95 494884 : if (obj->IsFeedbackVector()) FeedbackVector::cast(obj)->ClearSlots(isolate());
96 :
97 485337 : if (obj->IsJSObject()) {
98 223872 : JSObject* jsobj = JSObject::cast(obj);
99 223872 : if (jsobj->GetEmbedderFieldCount() > 0) {
100 : DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
101 150 : embedder_field_holders_.push_back(jsobj);
102 : }
103 : }
104 :
105 485337 : if (obj->IsHashTable()) CheckRehashability(obj);
106 :
107 : // Object has not yet been serialized. Serialize it here.
108 485337 : ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
109 485337 : serializer.Serialize();
110 : }
111 :
112 773247 : bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
113 : // Scripts should be referred only through shared function infos. We can't
114 : // allow them to be part of the partial snapshot because they contain a
115 : // unique ID, and deserializing several partial snapshots containing script
116 : // would cause dupes.
117 : DCHECK(!o->IsScript());
118 1737229 : return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
119 1528415 : o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
120 1258589 : o->IsTemplateInfo() ||
121 : o->map() ==
122 1258589 : startup_serializer_->isolate()->heap()->fixed_cow_array_map();
123 : }
124 :
125 151 : void PartialSerializer::SerializeEmbedderFields() {
126 267 : if (embedder_field_holders_.empty()) return;
127 : DisallowHeapAllocation no_gc;
128 335 : DisallowJavascriptExecution no_js(isolate());
129 : DisallowCompilation no_compile(isolate());
130 : DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
131 : sink_.Put(kEmbedderFieldsData, "embedder fields data");
132 185 : while (!embedder_field_holders_.empty()) {
133 : HandleScope scope(isolate());
134 150 : Handle<JSObject> obj(embedder_field_holders_.back(), isolate());
135 : embedder_field_holders_.pop_back();
136 150 : SerializerReference reference = reference_map()->Lookup(*obj);
137 : DCHECK(reference.is_back_reference());
138 150 : int embedder_fields_count = obj->GetEmbedderFieldCount();
139 480 : for (int i = 0; i < embedder_fields_count; i++) {
140 445 : if (obj->GetEmbedderField(i)->IsHeapObject()) continue;
141 :
142 : StartupData data = serialize_embedder_fields_.callback(
143 215 : v8::Utils::ToLocal(obj), i, serialize_embedder_fields_.data);
144 : sink_.Put(kNewObject + reference.space(), "embedder field holder");
145 215 : PutBackReference(*obj, reference);
146 215 : sink_.PutInt(i, "embedder field index");
147 215 : sink_.PutInt(data.raw_size, "embedder fields data size");
148 : sink_.PutRaw(reinterpret_cast<const byte*>(data.data), data.raw_size,
149 215 : "embedder fields data");
150 215 : delete[] data.data;
151 : }
152 : }
153 35 : sink_.Put(kSynchronize, "Finished with embedder fields data");
154 : }
155 :
156 327 : void PartialSerializer::CheckRehashability(HeapObject* table) {
157 : DCHECK(table->IsHashTable());
158 327 : if (!can_be_rehashed_) return;
159 302 : if (table->IsUnseededNumberDictionary()) return;
160 176 : if (table->IsOrderedHashMap() &&
161 : OrderedHashMap::cast(table)->NumberOfElements() == 0) {
162 : return;
163 : }
164 : // We can only correctly rehash if the global dictionary is the only hash
165 : // table that we deserialize.
166 176 : if (table == rehashable_global_dictionary_) return;
167 25 : can_be_rehashed_ = false;
168 : }
169 :
170 : } // namespace internal
171 : } // namespace v8
|