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