blob: eccbaabf5b718cc29aeb0c714d46332811bbab82 [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
131 BackReferenceMap* back_reference_map() { return &back_reference_map_; }
132 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
165 void PutBackReference(HeapObject* object, BackReference reference);
166
167 // Emit alignment prefix if necessary, return required padding space in bytes.
168 int PutAlignmentPrefix(HeapObject* object);
169
170 // Returns true if the object was successfully serialized.
171 bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
172 WhereToPoint where_to_point, int skip);
173
174 inline void FlushSkip(int skip) {
175 if (skip != 0) {
176 sink_->Put(kSkip, "SkipFromSerializeObject");
177 sink_->PutInt(skip, "SkipDistanceFromSerializeObject");
178 }
179 }
180
181 bool BackReferenceIsAlreadyAllocated(BackReference back_reference);
182
183 // This will return the space for an object.
184 BackReference AllocateLargeObject(int size);
185 BackReference Allocate(AllocationSpace space, int size);
186 int EncodeExternalReference(Address addr) {
187 return external_reference_encoder_.Encode(addr);
188 }
189
190 bool HasNotExceededFirstPageOfEachSpace();
191
192 // GetInt reads 4 bytes at once, requiring padding at the end.
193 void Pad();
194
195 // We may not need the code address map for logging for every instance
196 // of the serializer. Initialize it on demand.
197 void InitializeCodeAddressMap();
198
199 Code* CopyCode(Code* code);
200
201 inline uint32_t max_chunk_size(int space) const {
202 DCHECK_LE(0, space);
203 DCHECK_LT(space, kNumberOfSpaces);
204 return max_chunk_size_[space];
205 }
206
207 SnapshotByteSink* sink() const { return sink_; }
208
209 void QueueDeferredObject(HeapObject* obj) {
210 DCHECK(back_reference_map_.Lookup(obj).is_valid());
211 deferred_objects_.Add(obj);
212 }
213
214 void OutputStatistics(const char* name);
215
216 Isolate* isolate_;
217
218 SnapshotByteSink* sink_;
219 ExternalReferenceEncoder external_reference_encoder_;
220
221 BackReferenceMap back_reference_map_;
222 RootIndexMap root_index_map_;
223
224 int recursion_depth_;
225
226 friend class Deserializer;
227 friend class ObjectSerializer;
228 friend class RecursionScope;
229 friend class SnapshotData;
230
231 private:
232 CodeAddressMap* code_address_map_;
233 // Objects from the same space are put into chunks for bulk-allocation
234 // when deserializing. We have to make sure that each chunk fits into a
235 // page. So we track the chunk size in pending_chunk_ of a space, but
236 // when it exceeds a page, we complete the current chunk and start a new one.
237 uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
238 List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
239 uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
240
241 // We map serialized large objects to indexes for back-referencing.
242 uint32_t large_objects_total_size_;
243 uint32_t seen_large_objects_index_;
244
245 List<byte> code_buffer_;
246
247 // To handle stack overflow.
248 List<HeapObject*> deferred_objects_;
249
250#ifdef OBJECT_PRINT
251 static const int kInstanceTypes = 256;
252 int* instance_type_count_;
253 size_t* instance_type_size_;
254#endif // OBJECT_PRINT
255
256 DISALLOW_COPY_AND_ASSIGN(Serializer);
257};
258
259class Serializer::ObjectSerializer : public ObjectVisitor {
260 public:
261 ObjectSerializer(Serializer* serializer, HeapObject* obj,
262 SnapshotByteSink* sink, HowToCode how_to_code,
263 WhereToPoint where_to_point)
264 : serializer_(serializer),
265 object_(obj),
266 sink_(sink),
267 reference_representation_(how_to_code + where_to_point),
268 bytes_processed_so_far_(0),
269 code_has_been_output_(false) {}
270 ~ObjectSerializer() override {}
271 void Serialize();
272 void SerializeDeferred();
273 void VisitPointers(Object** start, Object** end) override;
274 void VisitEmbeddedPointer(RelocInfo* target) override;
275 void VisitExternalReference(Address* p) override;
276 void VisitExternalReference(RelocInfo* rinfo) override;
277 void VisitInternalReference(RelocInfo* rinfo) override;
278 void VisitCodeTarget(RelocInfo* target) override;
279 void VisitCodeEntry(Address entry_address) override;
280 void VisitCell(RelocInfo* rinfo) override;
281 void VisitRuntimeEntry(RelocInfo* reloc) override;
282 // Used for seralizing the external strings that hold the natives source.
283 void VisitExternalOneByteString(
284 v8::String::ExternalOneByteStringResource** resource) override;
285 // We can't serialize a heap with external two byte strings.
286 void VisitExternalTwoByteString(
287 v8::String::ExternalStringResource** resource) override {
288 UNREACHABLE();
289 }
290
291 private:
292 void SerializePrologue(AllocationSpace space, int size, Map* map);
293
294 bool SerializeExternalNativeSourceString(
295 int builtin_count,
296 v8::String::ExternalOneByteStringResource** resource_pointer,
297 FixedArray* source_cache, int resource_index);
298
299 enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
300 // This function outputs or skips the raw data between the last pointer and
301 // up to the current position. It optionally can just return the number of
302 // bytes to skip instead of performing a skip instruction, in case the skip
303 // can be merged into the next instruction.
304 int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
305 // External strings are serialized in a way to resemble sequential strings.
306 void SerializeExternalString();
307
308 Address PrepareCode();
309
310 Serializer* serializer_;
311 HeapObject* object_;
312 SnapshotByteSink* sink_;
313 int reference_representation_;
314 int bytes_processed_so_far_;
315 bool code_has_been_output_;
316};
317
318} // namespace internal
319} // namespace v8
320
321#endif // V8_SNAPSHOT_SERIALIZER_H_