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
18namespace v8 {
19namespace internal {
20
21class 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
130class 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
157class 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
287class RelocInfoIterator;
288
289class 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