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/objects-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 139 : PartialSerializer::PartialSerializer(
14 : Isolate* isolate, StartupSerializer* startup_serializer,
15 : v8::SerializeEmbedderFieldsCallback callback)
16 : : Serializer(isolate),
17 : startup_serializer_(startup_serializer),
18 278 : serialize_embedder_fields_(callback) {
19 139 : InitializeCodeAddressMap();
20 139 : }
21 :
22 278 : PartialSerializer::~PartialSerializer() {
23 139 : OutputStatistics("PartialSerializer");
24 139 : }
25 :
26 139 : void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
27 278 : if ((*o)->IsContext()) {
28 133 : Context* context = Context::cast(*o);
29 133 : reference_map()->AddAttachedReference(context->global_proxy());
30 : // The bootstrap snapshot has a code-stub context. When serializing the
31 : // partial snapshot, it is chained into the weak context list on the isolate
32 : // and it's next context pointer may point to the code-stub context. Clear
33 : // it before serializing, it will get re-added to the context list
34 : // explicitly when it's loaded.
35 133 : if (context->IsNativeContext()) {
36 : context->set(Context::NEXT_CONTEXT_LINK,
37 133 : isolate_->heap()->undefined_value());
38 : DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
39 : // Reset math random cache to get fresh random numbers.
40 : context->set_math_random_index(Smi::kZero);
41 133 : context->set_math_random_cache(isolate_->heap()->undefined_value());
42 : }
43 : }
44 139 : VisitRootPointer(Root::kPartialSnapshotCache, o);
45 139 : SerializeDeferredObjects();
46 139 : SerializeEmbedderFields();
47 139 : Pad();
48 139 : }
49 :
50 3130480 : void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
51 : WhereToPoint where_to_point, int skip) {
52 : if (obj->IsMap()) {
53 : // The code-caches link to context-specific code objects, which
54 : // the startup and context serializes cannot currently handle.
55 : DCHECK(Map::cast(obj)->code_cache() == obj->GetHeap()->empty_fixed_array());
56 : }
57 :
58 : // Replace typed arrays by undefined.
59 3130480 : if (obj->IsJSTypedArray()) obj = isolate_->heap()->undefined_value();
60 :
61 5706797 : if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
62 :
63 2471613 : int root_index = root_index_map_.Lookup(obj);
64 2471613 : if (root_index != RootIndexMap::kInvalidRootIndex) {
65 1172549 : PutRoot(root_index, obj, how_to_code, where_to_point, skip);
66 1172549 : return;
67 : }
68 :
69 1299064 : if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
70 :
71 1006447 : if (ShouldBeInThePartialSnapshotCache(obj)) {
72 452284 : FlushSkip(skip);
73 :
74 452284 : int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
75 : sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
76 452284 : "PartialSnapshotCache");
77 452284 : sink_.PutInt(cache_index, "partial_snapshot_cache_index");
78 452284 : return;
79 : }
80 :
81 : // Pointers from the partial snapshot to the objects in the startup snapshot
82 : // should go through the root array or through the partial snapshot cache.
83 : // If this is not the case you may have to add something to the root array.
84 : DCHECK(!startup_serializer_->reference_map()->Lookup(obj).is_valid());
85 : // All the internalized strings that the partial snapshot needs should be
86 : // either in the root table or in the partial snapshot cache.
87 : DCHECK(!obj->IsInternalizedString());
88 : // Function and object templates are not context specific.
89 : DCHECK(!obj->IsTemplateInfo());
90 :
91 554163 : FlushSkip(skip);
92 :
93 : // Clear literal boilerplates.
94 554163 : if (obj->IsJSFunction()) {
95 : JSFunction* function = JSFunction::cast(obj);
96 160111 : function->ClearTypeFeedbackInfo();
97 : }
98 :
99 554163 : if (obj->IsJSObject()) {
100 : JSObject* jsobj = JSObject::cast(obj);
101 232448 : if (jsobj->GetEmbedderFieldCount() > 0) {
102 : DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
103 60 : embedder_field_holders_.Add(jsobj);
104 : }
105 : }
106 :
107 : // Object has not yet been serialized. Serialize it here.
108 554163 : ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
109 554163 : serializer.Serialize();
110 : }
111 :
112 1006447 : 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 2407652 : return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
119 1719104 : o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
120 1560616 : o->IsTemplateInfo() ||
121 : o->map() ==
122 1560616 : startup_serializer_->isolate()->heap()->fixed_cow_array_map();
123 : }
124 :
125 139 : void PartialSerializer::SerializeEmbedderFields() {
126 211 : int count = embedder_field_holders_.length();
127 266 : if (count == 0) return;
128 : DisallowHeapAllocation no_gc;
129 72 : DisallowJavascriptExecution no_js(isolate());
130 : DisallowCompilation no_compile(isolate());
131 : DCHECK_NOT_NULL(serialize_embedder_fields_.callback);
132 : sink_.Put(kEmbedderFieldsData, "embedder fields data");
133 72 : while (embedder_field_holders_.length() > 0) {
134 : HandleScope scope(isolate());
135 60 : Handle<JSObject> obj(embedder_field_holders_.RemoveLast(), isolate());
136 60 : SerializerReference reference = reference_map_.Lookup(*obj);
137 : DCHECK(reference.is_back_reference());
138 60 : int embedder_fields_count = obj->GetEmbedderFieldCount();
139 216 : for (int i = 0; i < embedder_fields_count; i++) {
140 294 : if (obj->GetEmbedderField(i)->IsHeapObject()) continue;
141 : StartupData data = serialize_embedder_fields_.callback(
142 18 : v8::Utils::ToLocal(obj), i, serialize_embedder_fields_.data);
143 : sink_.Put(kNewObject + reference.space(), "embedder field holder");
144 18 : PutBackReference(*obj, reference);
145 18 : sink_.PutInt(i, "embedder field index");
146 18 : sink_.PutInt(data.raw_size, "embedder fields data size");
147 : sink_.PutRaw(reinterpret_cast<const byte*>(data.data), data.raw_size,
148 18 : "embedder fields data");
149 18 : delete[] data.data;
150 : }
151 : }
152 12 : sink_.Put(kSynchronize, "Finished with embedder fields data");
153 : }
154 :
155 : } // namespace internal
156 : } // namespace v8
|