blob: f99cd7202581d95f8d5a790baffae42d339b9414 [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// 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 "src/isolate.h"
9#include "src/log.h"
10#include "src/objects.h"
11#include "src/snapshot/serializer-common.h"
12#include "src/snapshot/snapshot-source-sink.h"
13
14namespace v8 {
15namespace internal {
16
17class CodeAddressMap : public CodeEventLogger {
18 public:
19 explicit CodeAddressMap(Isolate* isolate) : isolate_(isolate) {
20 isolate->logger()->addCodeEventListener(this);
21 }
22
23 ~CodeAddressMap() override {
24 isolate_->logger()->removeCodeEventListener(this);
25 }
26
27 void CodeMoveEvent(AbstractCode* from, Address to) override {
28 address_to_name_map_.Move(from->address(), to);
29 }
30
31 void CodeDisableOptEvent(AbstractCode* code,
32 SharedFunctionInfo* shared) override {}
33
34 const char* Lookup(Address address) {
35 return address_to_name_map_.Lookup(address);
36 }
37
38 private:
39 class NameMap {
40 public:
41 NameMap() : impl_(HashMap::PointersMatch) {}
42
43 ~NameMap() {
44 for (HashMap::Entry* p = impl_.Start(); p != NULL; p = impl_.Next(p)) {
45 DeleteArray(static_cast<const char*>(p->value));
46 }
47 }
48
49 void Insert(Address code_address, const char* name, int name_size) {
50 HashMap::Entry* entry = FindOrCreateEntry(code_address);
51 if (entry->value == NULL) {
52 entry->value = CopyName(name, name_size);
53 }
54 }
55
56 const char* Lookup(Address code_address) {
57 HashMap::Entry* entry = FindEntry(code_address);
58 return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
59 }
60
61 void Remove(Address code_address) {
62 HashMap::Entry* entry = FindEntry(code_address);
63 if (entry != NULL) {
64 DeleteArray(static_cast<char*>(entry->value));
65 RemoveEntry(entry);
66 }
67 }
68
69 void Move(Address from, Address to) {
70 if (from == to) return;
71 HashMap::Entry* from_entry = FindEntry(from);
72 DCHECK(from_entry != NULL);
73 void* value = from_entry->value;
74 RemoveEntry(from_entry);
75 HashMap::Entry* to_entry = FindOrCreateEntry(to);
76 DCHECK(to_entry->value == NULL);
77 to_entry->value = value;
78 }
79
80 private:
81 static char* CopyName(const char* name, int name_size) {
82 char* result = NewArray<char>(name_size + 1);
83 for (int i = 0; i < name_size; ++i) {
84 char c = name[i];
85 if (c == '\0') c = ' ';
86 result[i] = c;
87 }
88 result[name_size] = '\0';
89 return result;
90 }
91
92 HashMap::Entry* FindOrCreateEntry(Address code_address) {
93 return impl_.LookupOrInsert(code_address,
94 ComputePointerHash(code_address));
95 }
96
97 HashMap::Entry* FindEntry(Address code_address) {
98 return impl_.Lookup(code_address, ComputePointerHash(code_address));
99 }
100
101 void RemoveEntry(HashMap::Entry* entry) {
102 impl_.Remove(entry->key, entry->hash);
103 }
104
105 HashMap impl_;
106
107 DISALLOW_COPY_AND_ASSIGN(NameMap);
108 };
109
110 void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
111 const char* name, int length) override {
112 address_to_name_map_.Insert(code->address(), name, length);
113 }
114
115 NameMap address_to_name_map_;
116 Isolate* isolate_;
117};
118
119// There can be only one serializer per V8 process.
120class Serializer : public SerializerDeserializer {
121 public:
122 Serializer(Isolate* isolate, SnapshotByteSink* sink);
123 ~Serializer() override;
124
125 void EncodeReservations(List<SerializedData::Reservation>* out) const;
126
127 void SerializeDeferredObjects();
128
129 Isolate* isolate() const { return isolate_; }
130
Ben Murdochc5610432016-08-08 18:44:38 +0100131 SerializerReferenceMap* reference_map() { return &reference_map_; }
Ben Murdochda12d292016-06-02 14:46:10 +0100132 RootIndexMap* root_index_map() { return &root_index_map_; }
133
134#ifdef OBJECT_PRINT
135 void CountInstanceType(Map* map, int size);
136#endif // OBJECT_PRINT
137
138 protected:
139 class ObjectSerializer;
140 class RecursionScope {
141 public:
142 explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
143 serializer_->recursion_depth_++;
144 }
145 ~RecursionScope() { serializer_->recursion_depth_--; }
146 bool ExceedsMaximum() {
147 return serializer_->recursion_depth_ >= kMaxRecursionDepth;
148 }
149
150 private:
151 static const int kMaxRecursionDepth = 32;
152 Serializer* serializer_;
153 };
154
155 virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
156 WhereToPoint where_to_point, int skip) = 0;
157
158 void VisitPointers(Object** start, Object** end) override;
159
160 void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
161 int skip);
162
163 void PutSmi(Smi* smi);
164
Ben Murdochc5610432016-08-08 18:44:38 +0100165 void PutBackReference(HeapObject* object, SerializerReference reference);
166
167 void PutAttachedReference(SerializerReference reference,
168 HowToCode how_to_code, WhereToPoint where_to_point);
Ben Murdochda12d292016-06-02 14:46:10 +0100169
170 // Emit alignment prefix if necessary, return required padding space in bytes.
171 int PutAlignmentPrefix(HeapObject* object);
172
173 // Returns true if the object was successfully serialized.
174 bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
175 WhereToPoint where_to_point, int skip);
176
177 inline void FlushSkip(int skip) {
178 if (skip != 0) {
179 sink_->Put(kSkip, "SkipFromSerializeObject");
180 sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
181 }
182 }
183
Ben Murdochc5610432016-08-08 18:44:38 +0100184 bool BackReferenceIsAlreadyAllocated(SerializerReference back_reference);
Ben Murdochda12d292016-06-02 14:46:10 +0100185
186 // This will return the space for an object.
Ben Murdochc5610432016-08-08 18:44:38 +0100187 SerializerReference AllocateLargeObject(int size);
188 SerializerReference Allocate(AllocationSpace space, int size);
Ben Murdochda12d292016-06-02 14:46:10 +0100189 int EncodeExternalReference(Address addr) {
190 return external_reference_encoder_.Encode(addr);
191 }
192
193 bool HasNotExceededFirstPageOfEachSpace();
194
195 // GetInt reads 4 bytes at once, requiring padding at the end.
196 void Pad();
197
198 // We may not need the code address map for logging for every instance
199 // of the serializer. Initialize it on demand.
200 void InitializeCodeAddressMap();
201
202 Code* CopyCode(Code* code);
203
204 inline uint32_t max_chunk_size(int space) const {
205 DCHECK_LE(0, space);
206 DCHECK_LT(space, kNumberOfSpaces);
207 return max_chunk_size_[space];
208 }
209
210 SnapshotByteSink* sink() const { return sink_; }
211
212 void QueueDeferredObject(HeapObject* obj) {
Ben Murdochc5610432016-08-08 18:44:38 +0100213 DCHECK(reference_map_.Lookup(obj).is_back_reference());
Ben Murdochda12d292016-06-02 14:46:10 +0100214 deferred_objects_.Add(obj);
215 }
216
217 void OutputStatistics(const char* name);
218
219 Isolate* isolate_;
220
221 SnapshotByteSink* sink_;
222 ExternalReferenceEncoder external_reference_encoder_;
223
Ben Murdochc5610432016-08-08 18:44:38 +0100224 SerializerReferenceMap reference_map_;
Ben Murdochda12d292016-06-02 14:46:10 +0100225 RootIndexMap root_index_map_;
226
227 int recursion_depth_;
228
229 friend class Deserializer;
230 friend class ObjectSerializer;
231 friend class RecursionScope;
232 friend class SnapshotData;
233
234 private:
235 CodeAddressMap* code_address_map_;
236 // Objects from the same space are put into chunks for bulk-allocation
237 // when deserializing. We have to make sure that each chunk fits into a
238 // page. So we track the chunk size in pending_chunk_ of a space, but
239 // when it exceeds a page, we complete the current chunk and start a new one.
240 uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
241 List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
242 uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
243
244 // We map serialized large objects to indexes for back-referencing.
245 uint32_t large_objects_total_size_;
246 uint32_t seen_large_objects_index_;
247
248 List<byte> code_buffer_;
249
250 // To handle stack overflow.
251 List<HeapObject*> deferred_objects_;
252
253#ifdef OBJECT_PRINT
254 static const int kInstanceTypes = 256;
255 int* instance_type_count_;
256 size_t* instance_type_size_;
257#endif // OBJECT_PRINT
258
259 DISALLOW_COPY_AND_ASSIGN(Serializer);
260};
261
262class Serializer::ObjectSerializer : public ObjectVisitor {
263 public:
264 ObjectSerializer(Serializer* serializer, HeapObject* obj,
265 SnapshotByteSink* sink, HowToCode how_to_code,
266 WhereToPoint where_to_point)
267 : serializer_(serializer),
268 object_(obj),
269 sink_(sink),
270 reference_representation_(how_to_code + where_to_point),
271 bytes_processed_so_far_(0),
272 code_has_been_output_(false) {}
273 ~ObjectSerializer() override {}
274 void Serialize();
275 void SerializeDeferred();
276 void VisitPointers(Object** start, Object** end) override;
277 void VisitEmbeddedPointer(RelocInfo* target) override;
278 void VisitExternalReference(Address* p) override;
279 void VisitExternalReference(RelocInfo* rinfo) override;
280 void VisitInternalReference(RelocInfo* rinfo) override;
281 void VisitCodeTarget(RelocInfo* target) override;
282 void VisitCodeEntry(Address entry_address) override;
283 void VisitCell(RelocInfo* rinfo) override;
284 void VisitRuntimeEntry(RelocInfo* reloc) override;
285 // Used for seralizing the external strings that hold the natives source.
286 void VisitExternalOneByteString(
287 v8::String::ExternalOneByteStringResource** resource) override;
288 // We can't serialize a heap with external two byte strings.
289 void VisitExternalTwoByteString(
290 v8::String::ExternalStringResource** resource) override {
291 UNREACHABLE();
292 }
293
294 private:
295 void SerializePrologue(AllocationSpace space, int size, Map* map);
296
297 bool SerializeExternalNativeSourceString(
298 int builtin_count,
299 v8::String::ExternalOneByteStringResource** resource_pointer,
300 FixedArray* source_cache, int resource_index);
301
302 enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
303 // This function outputs or skips the raw data between the last pointer and
304 // up to the current position. It optionally can just return the number of
305 // bytes to skip instead of performing a skip instruction, in case the skip
306 // can be merged into the next instruction.
307 int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
308 // External strings are serialized in a way to resemble sequential strings.
309 void SerializeExternalString();
310
311 Address PrepareCode();
312
313 Serializer* serializer_;
314 HeapObject* object_;
315 SnapshotByteSink* sink_;
316 int reference_representation_;
317 int bytes_processed_so_far_;
318 bool code_has_been_output_;
319};
320
321} // namespace internal
322} // namespace v8
323
324#endif // V8_SNAPSHOT_SERIALIZER_H_