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 | #ifndef V8_SNAPSHOT_SERIALIZER_H_ |
6 | #define V8_SNAPSHOT_SERIALIZER_H_ |
7 | |
8 | #include <map> |
9 | |
10 | #include "src/isolate.h" |
11 | #include "src/log.h" |
12 | #include "src/objects.h" |
13 | #include "src/snapshot/embedded-data.h" |
14 | #include "src/snapshot/serializer-allocator.h" |
15 | #include "src/snapshot/serializer-common.h" |
16 | #include "src/snapshot/snapshot-source-sink.h" |
17 | |
18 | namespace v8 { |
19 | namespace internal { |
20 | |
21 | class CodeAddressMap : public CodeEventLogger { |
22 | public: |
23 | explicit CodeAddressMap(Isolate* isolate) : CodeEventLogger(isolate) { |
24 | isolate->logger()->AddCodeEventListener(this); |
25 | } |
26 | |
27 | ~CodeAddressMap() override { |
28 | isolate_->logger()->RemoveCodeEventListener(this); |
29 | } |
30 | |
31 | void CodeMoveEvent(AbstractCode from, AbstractCode to) override { |
32 | address_to_name_map_.Move(from->address(), to->address()); |
33 | } |
34 | |
35 | void CodeDisableOptEvent(AbstractCode code, |
36 | SharedFunctionInfo shared) override {} |
37 | |
38 | const char* Lookup(Address address) { |
39 | return address_to_name_map_.Lookup(address); |
40 | } |
41 | |
42 | private: |
43 | class NameMap { |
44 | public: |
45 | NameMap() : impl_() {} |
46 | |
47 | ~NameMap() { |
48 | for (base::HashMap::Entry* p = impl_.Start(); p != nullptr; |
49 | p = impl_.Next(p)) { |
50 | DeleteArray(static_cast<const char*>(p->value)); |
51 | } |
52 | } |
53 | |
54 | void Insert(Address code_address, const char* name, int name_size) { |
55 | base::HashMap::Entry* entry = FindOrCreateEntry(code_address); |
56 | if (entry->value == nullptr) { |
57 | entry->value = CopyName(name, name_size); |
58 | } |
59 | } |
60 | |
61 | const char* Lookup(Address code_address) { |
62 | base::HashMap::Entry* entry = FindEntry(code_address); |
63 | return (entry != nullptr) ? static_cast<const char*>(entry->value) |
64 | : nullptr; |
65 | } |
66 | |
67 | void Remove(Address code_address) { |
68 | base::HashMap::Entry* entry = FindEntry(code_address); |
69 | if (entry != nullptr) { |
70 | DeleteArray(static_cast<char*>(entry->value)); |
71 | RemoveEntry(entry); |
72 | } |
73 | } |
74 | |
75 | void Move(Address from, Address to) { |
76 | if (from == to) return; |
77 | base::HashMap::Entry* from_entry = FindEntry(from); |
78 | DCHECK_NOT_NULL(from_entry); |
79 | void* value = from_entry->value; |
80 | RemoveEntry(from_entry); |
81 | base::HashMap::Entry* to_entry = FindOrCreateEntry(to); |
82 | DCHECK_NULL(to_entry->value); |
83 | to_entry->value = value; |
84 | } |
85 | |
86 | private: |
87 | static char* CopyName(const char* name, int name_size) { |
88 | char* result = NewArray<char>(name_size + 1); |
89 | for (int i = 0; i < name_size; ++i) { |
90 | char c = name[i]; |
91 | if (c == '\0') c = ' '; |
92 | result[i] = c; |
93 | } |
94 | result[name_size] = '\0'; |
95 | return result; |
96 | } |
97 | |
98 | base::HashMap::Entry* FindOrCreateEntry(Address code_address) { |
99 | return impl_.LookupOrInsert(reinterpret_cast<void*>(code_address), |
100 | ComputeAddressHash(code_address)); |
101 | } |
102 | |
103 | base::HashMap::Entry* FindEntry(Address code_address) { |
104 | return impl_.Lookup(reinterpret_cast<void*>(code_address), |
105 | ComputeAddressHash(code_address)); |
106 | } |
107 | |
108 | void RemoveEntry(base::HashMap::Entry* entry) { |
109 | impl_.Remove(entry->key, entry->hash); |
110 | } |
111 | |
112 | base::HashMap impl_; |
113 | |
114 | DISALLOW_COPY_AND_ASSIGN(NameMap); |
115 | }; |
116 | |
117 | void LogRecordedBuffer(AbstractCode code, SharedFunctionInfo, |
118 | const char* name, int length) override { |
119 | address_to_name_map_.Insert(code->address(), name, length); |
120 | } |
121 | |
122 | void LogRecordedBuffer(const wasm::WasmCode* code, const char* name, |
123 | int length) override { |
124 | UNREACHABLE(); |
125 | } |
126 | |
127 | NameMap address_to_name_map_; |
128 | }; |
129 | |
130 | class ObjectCacheIndexMap { |
131 | public: |
132 | ObjectCacheIndexMap() : map_(), next_index_(0) {} |
133 | |
134 | // If |obj| is in the map, immediately return true. Otherwise add it to the |
135 | // map and return false. In either case set |*index_out| to the index |
136 | // associated with the map. |
137 | bool LookupOrInsert(HeapObject obj, int* index_out) { |
138 | Maybe<uint32_t> maybe_index = map_.Get(obj); |
139 | if (maybe_index.IsJust()) { |
140 | *index_out = maybe_index.FromJust(); |
141 | return true; |
142 | } |
143 | *index_out = next_index_; |
144 | map_.Set(obj, next_index_++); |
145 | return false; |
146 | } |
147 | |
148 | private: |
149 | DisallowHeapAllocation no_allocation_; |
150 | |
151 | HeapObjectToIndexHashMap map_; |
152 | int next_index_; |
153 | |
154 | DISALLOW_COPY_AND_ASSIGN(ObjectCacheIndexMap); |
155 | }; |
156 | |
157 | class Serializer : public SerializerDeserializer { |
158 | public: |
159 | explicit Serializer(Isolate* isolate); |
160 | ~Serializer() override; |
161 | |
162 | std::vector<SerializedData::Reservation> EncodeReservations() const { |
163 | return allocator_.EncodeReservations(); |
164 | } |
165 | |
166 | const std::vector<byte>* Payload() const { return sink_.data(); } |
167 | |
168 | bool ReferenceMapContains(HeapObject o) { |
169 | return reference_map() |
170 | ->LookupReference(reinterpret_cast<void*>(o->ptr())) |
171 | .is_valid(); |
172 | } |
173 | |
174 | Isolate* isolate() const { return isolate_; } |
175 | |
176 | protected: |
177 | class ObjectSerializer; |
178 | class RecursionScope { |
179 | public: |
180 | explicit RecursionScope(Serializer* serializer) : serializer_(serializer) { |
181 | serializer_->recursion_depth_++; |
182 | } |
183 | ~RecursionScope() { serializer_->recursion_depth_--; } |
184 | bool ExceedsMaximum() { |
185 | return serializer_->recursion_depth_ >= kMaxRecursionDepth; |
186 | } |
187 | |
188 | private: |
189 | static const int kMaxRecursionDepth = 32; |
190 | Serializer* serializer_; |
191 | }; |
192 | |
193 | void SerializeDeferredObjects(); |
194 | virtual void SerializeObject(HeapObject o) = 0; |
195 | |
196 | virtual bool MustBeDeferred(HeapObject object); |
197 | |
198 | void VisitRootPointers(Root root, const char* description, |
199 | FullObjectSlot start, FullObjectSlot end) override; |
200 | void SerializeRootObject(Object object); |
201 | |
202 | void PutRoot(RootIndex root_index, HeapObject object); |
203 | void PutSmi(Smi smi); |
204 | void PutBackReference(HeapObject object, SerializerReference reference); |
205 | void PutAttachedReference(SerializerReference reference); |
206 | // Emit alignment prefix if necessary, return required padding space in bytes. |
207 | int PutAlignmentPrefix(HeapObject object); |
208 | void PutNextChunk(int space); |
209 | void PutRepeat(int repeat_count); |
210 | |
211 | // Returns true if the object was successfully serialized as a root. |
212 | bool SerializeRoot(HeapObject obj); |
213 | |
214 | // Returns true if the object was successfully serialized as hot object. |
215 | bool SerializeHotObject(HeapObject obj); |
216 | |
217 | // Returns true if the object was successfully serialized as back reference. |
218 | bool SerializeBackReference(HeapObject obj); |
219 | |
220 | // Returns true if the given heap object is a bytecode handler code object. |
221 | bool ObjectIsBytecodeHandler(HeapObject obj) const; |
222 | |
223 | ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) { |
224 | return external_reference_encoder_.Encode(addr); |
225 | } |
226 | |
227 | // GetInt reads 4 bytes at once, requiring padding at the end. |
228 | // Use padding_offset to specify the space you want to use after padding. |
229 | void Pad(int padding_offset = 0); |
230 | |
231 | // We may not need the code address map for logging for every instance |
232 | // of the serializer. Initialize it on demand. |
233 | void InitializeCodeAddressMap(); |
234 | |
235 | Code CopyCode(Code code); |
236 | |
237 | void QueueDeferredObject(HeapObject obj) { |
238 | DCHECK(reference_map_.LookupReference(reinterpret_cast<void*>(obj->ptr())) |
239 | .is_back_reference()); |
240 | deferred_objects_.push_back(obj); |
241 | } |
242 | |
243 | void OutputStatistics(const char* name); |
244 | |
245 | #ifdef OBJECT_PRINT |
246 | void CountInstanceType(Map map, int size, AllocationSpace space); |
247 | #endif // OBJECT_PRINT |
248 | |
249 | #ifdef DEBUG |
250 | void PushStack(HeapObject o) { stack_.push_back(o); } |
251 | void PopStack() { stack_.pop_back(); } |
252 | void PrintStack(); |
253 | #endif // DEBUG |
254 | |
255 | SerializerReferenceMap* reference_map() { return &reference_map_; } |
256 | const RootIndexMap* root_index_map() const { return &root_index_map_; } |
257 | SerializerAllocator* allocator() { return &allocator_; } |
258 | |
259 | SnapshotByteSink sink_; // Used directly by subclasses. |
260 | |
261 | private: |
262 | Isolate* isolate_; |
263 | SerializerReferenceMap reference_map_; |
264 | ExternalReferenceEncoder external_reference_encoder_; |
265 | RootIndexMap root_index_map_; |
266 | CodeAddressMap* code_address_map_ = nullptr; |
267 | std::vector<byte> code_buffer_; |
268 | std::vector<HeapObject> deferred_objects_; // To handle stack overflow. |
269 | int recursion_depth_ = 0; |
270 | SerializerAllocator allocator_; |
271 | |
272 | #ifdef OBJECT_PRINT |
273 | static const int kInstanceTypes = LAST_TYPE + 1; |
274 | int* instance_type_count_[LAST_SPACE]; |
275 | size_t* instance_type_size_[LAST_SPACE]; |
276 | #endif // OBJECT_PRINT |
277 | |
278 | #ifdef DEBUG |
279 | std::vector<HeapObject> stack_; |
280 | #endif // DEBUG |
281 | |
282 | friend class SerializerAllocator; |
283 | |
284 | DISALLOW_COPY_AND_ASSIGN(Serializer); |
285 | }; |
286 | |
287 | class RelocInfoIterator; |
288 | |
289 | class Serializer::ObjectSerializer : public ObjectVisitor { |
290 | public: |
291 | ObjectSerializer(Serializer* serializer, HeapObject obj, |
292 | SnapshotByteSink* sink) |
293 | : serializer_(serializer), |
294 | object_(obj), |
295 | sink_(sink), |
296 | bytes_processed_so_far_(0) { |
297 | #ifdef DEBUG |
298 | serializer_->PushStack(obj); |
299 | #endif // DEBUG |
300 | } |
301 | // NOLINTNEXTLINE (modernize-use-equals-default) |
302 | ~ObjectSerializer() override { |
303 | #ifdef DEBUG |
304 | serializer_->PopStack(); |
305 | #endif // DEBUG |
306 | } |
307 | void Serialize(); |
308 | void SerializeObject(); |
309 | void SerializeDeferred(); |
310 | void VisitPointers(HeapObject host, ObjectSlot start, |
311 | ObjectSlot end) override; |
312 | void VisitPointers(HeapObject host, MaybeObjectSlot start, |
313 | MaybeObjectSlot end) override; |
314 | void VisitEmbeddedPointer(Code host, RelocInfo* target) override; |
315 | void VisitExternalReference(Foreign host, Address* p) override; |
316 | void VisitExternalReference(Code host, RelocInfo* rinfo) override; |
317 | void VisitInternalReference(Code host, RelocInfo* rinfo) override; |
318 | void VisitCodeTarget(Code host, RelocInfo* target) override; |
319 | void VisitRuntimeEntry(Code host, RelocInfo* reloc) override; |
320 | void VisitOffHeapTarget(Code host, RelocInfo* target) override; |
321 | |
322 | private: |
323 | void SerializePrologue(AllocationSpace space, int size, Map map); |
324 | |
325 | // This function outputs or skips the raw data between the last pointer and |
326 | // up to the current position. |
327 | void SerializeContent(Map map, int size); |
328 | void OutputRawData(Address up_to); |
329 | void OutputCode(int size); |
330 | int32_t SerializeBackingStore(void* backing_store, int32_t byte_length); |
331 | void SerializeJSTypedArray(); |
332 | void SerializeJSArrayBuffer(); |
333 | void SerializeExternalString(); |
334 | void SerializeExternalStringAsSequentialString(); |
335 | |
336 | Serializer* serializer_; |
337 | HeapObject object_; |
338 | SnapshotByteSink* sink_; |
339 | int bytes_processed_so_far_; |
340 | }; |
341 | |
342 | } // namespace internal |
343 | } // namespace v8 |
344 | |
345 | #endif // V8_SNAPSHOT_SERIALIZER_H_ |
346 | |