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