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
PartialSerializer(Isolate * isolate,StartupSerializer * startup_serializer,v8::SerializeInternalFieldsCallback callback)13 PartialSerializer::PartialSerializer(
14 Isolate* isolate, StartupSerializer* startup_serializer,
15 v8::SerializeInternalFieldsCallback callback)
16 : Serializer(isolate),
17 startup_serializer_(startup_serializer),
18 serialize_internal_fields_(callback) {
19 InitializeCodeAddressMap();
20 }
21
~PartialSerializer()22 PartialSerializer::~PartialSerializer() {
23 OutputStatistics("PartialSerializer");
24 }
25
Serialize(Object ** o)26 void PartialSerializer::Serialize(Object** o) {
27 if ((*o)->IsContext()) {
28 Context* context = Context::cast(*o);
29 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 if (context->IsNativeContext()) {
36 context->set(Context::NEXT_CONTEXT_LINK,
37 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 context->set_math_random_cache(isolate_->heap()->undefined_value());
42 }
43 }
44 VisitPointer(o);
45 SerializeDeferredObjects();
46 SerializeInternalFields();
47 Pad();
48 }
49
SerializeObject(HeapObject * obj,HowToCode how_to_code,WhereToPoint where_to_point,int skip)50 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 if (obj->IsJSTypedArray()) obj = isolate_->heap()->undefined_value();
60
61 if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return;
62
63 int root_index = root_index_map_.Lookup(obj);
64 if (root_index != RootIndexMap::kInvalidRootIndex) {
65 PutRoot(root_index, obj, how_to_code, where_to_point, skip);
66 return;
67 }
68
69 if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return;
70
71 if (ShouldBeInThePartialSnapshotCache(obj)) {
72 FlushSkip(skip);
73
74 int cache_index = startup_serializer_->PartialSnapshotCacheIndex(obj);
75 sink_.Put(kPartialSnapshotCache + how_to_code + where_to_point,
76 "PartialSnapshotCache");
77 sink_.PutInt(cache_index, "partial_snapshot_cache_index");
78 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 FlushSkip(skip);
92
93 // Clear literal boilerplates.
94 if (obj->IsJSFunction()) {
95 JSFunction* function = JSFunction::cast(obj);
96 LiteralsArray* literals = function->literals();
97 for (int i = 0; i < literals->literals_count(); i++) {
98 literals->set_literal_undefined(i);
99 }
100 function->ClearTypeFeedbackInfo();
101 }
102
103 if (obj->IsJSObject()) {
104 JSObject* jsobj = JSObject::cast(obj);
105 if (jsobj->GetInternalFieldCount() > 0) internal_field_holders_.Add(jsobj);
106 }
107
108 // Object has not yet been serialized. Serialize it here.
109 ObjectSerializer serializer(this, obj, &sink_, how_to_code, where_to_point);
110 serializer.Serialize();
111 }
112
ShouldBeInThePartialSnapshotCache(HeapObject * o)113 bool PartialSerializer::ShouldBeInThePartialSnapshotCache(HeapObject* o) {
114 // Scripts should be referred only through shared function infos. We can't
115 // allow them to be part of the partial snapshot because they contain a
116 // unique ID, and deserializing several partial snapshots containing script
117 // would cause dupes.
118 DCHECK(!o->IsScript());
119 return o->IsName() || o->IsSharedFunctionInfo() || o->IsHeapNumber() ||
120 o->IsCode() || o->IsScopeInfo() || o->IsAccessorInfo() ||
121 o->IsTemplateInfo() ||
122 o->map() ==
123 startup_serializer_->isolate()->heap()->fixed_cow_array_map();
124 }
125
SerializeInternalFields()126 void PartialSerializer::SerializeInternalFields() {
127 int count = internal_field_holders_.length();
128 if (count == 0) return;
129 DisallowHeapAllocation no_gc;
130 DisallowJavascriptExecution no_js(isolate());
131 DisallowCompilation no_compile(isolate());
132 DCHECK_NOT_NULL(serialize_internal_fields_);
133 sink_.Put(kInternalFieldsData, "internal fields data");
134 while (internal_field_holders_.length() > 0) {
135 HandleScope scope(isolate());
136 Handle<JSObject> obj(internal_field_holders_.RemoveLast(), isolate());
137 SerializerReference reference = reference_map_.Lookup(*obj);
138 DCHECK(reference.is_back_reference());
139 int internal_fields_count = obj->GetInternalFieldCount();
140 for (int i = 0; i < internal_fields_count; i++) {
141 if (obj->GetInternalField(i)->IsHeapObject()) continue;
142 StartupData data = serialize_internal_fields_(v8::Utils::ToLocal(obj), i);
143 sink_.Put(kNewObject + reference.space(), "internal field holder");
144 PutBackReference(*obj, reference);
145 sink_.PutInt(i, "internal field index");
146 sink_.PutInt(data.raw_size, "internal fields data size");
147 sink_.PutRaw(reinterpret_cast<const byte*>(data.data), data.raw_size,
148 "internal fields data");
149 delete[] data.data;
150 }
151 }
152 sink_.Put(kSynchronize, "Finished with internal fields data");
153 }
154
155 } // namespace internal
156 } // namespace v8
157