• 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 <map>
9 
10 #include "src/codegen/external-reference-encoder.h"
11 #include "src/common/assert-scope.h"
12 #include "src/execution/isolate.h"
13 #include "src/handles/global-handles.h"
14 #include "src/logging/log.h"
15 #include "src/objects/objects.h"
16 #include "src/snapshot/embedded/embedded-data.h"
17 #include "src/snapshot/serializer-deserializer.h"
18 #include "src/snapshot/snapshot-source-sink.h"
19 #include "src/snapshot/snapshot.h"
20 #include "src/utils/identity-map.h"
21 
22 namespace v8 {
23 namespace internal {
24 
25 class CodeAddressMap : public CodeEventLogger {
26  public:
CodeAddressMap(Isolate * isolate)27   explicit CodeAddressMap(Isolate* isolate) : CodeEventLogger(isolate) {
28     isolate->logger()->AddCodeEventListener(this);
29   }
30 
~CodeAddressMap()31   ~CodeAddressMap() override {
32     isolate_->logger()->RemoveCodeEventListener(this);
33   }
34 
CodeMoveEvent(AbstractCode from,AbstractCode to)35   void CodeMoveEvent(AbstractCode from, AbstractCode to) override {
36     address_to_name_map_.Move(from.address(), to.address());
37   }
38 
CodeDisableOptEvent(Handle<AbstractCode> code,Handle<SharedFunctionInfo> shared)39   void CodeDisableOptEvent(Handle<AbstractCode> code,
40                            Handle<SharedFunctionInfo> shared) override {}
41 
Lookup(Address address)42   const char* Lookup(Address address) {
43     return address_to_name_map_.Lookup(address);
44   }
45 
46  private:
47   class NameMap {
48    public:
NameMap()49     NameMap() : impl_() {}
50     NameMap(const NameMap&) = delete;
51     NameMap& operator=(const NameMap&) = delete;
52 
~NameMap()53     ~NameMap() {
54       for (base::HashMap::Entry* p = impl_.Start(); p != nullptr;
55            p = impl_.Next(p)) {
56         DeleteArray(static_cast<const char*>(p->value));
57       }
58     }
59 
Insert(Address code_address,const char * name,int name_size)60     void Insert(Address code_address, const char* name, int name_size) {
61       base::HashMap::Entry* entry = FindOrCreateEntry(code_address);
62       if (entry->value == nullptr) {
63         entry->value = CopyName(name, name_size);
64       }
65     }
66 
Lookup(Address code_address)67     const char* Lookup(Address code_address) {
68       base::HashMap::Entry* entry = FindEntry(code_address);
69       return (entry != nullptr) ? static_cast<const char*>(entry->value)
70                                 : nullptr;
71     }
72 
Remove(Address code_address)73     void Remove(Address code_address) {
74       base::HashMap::Entry* entry = FindEntry(code_address);
75       if (entry != nullptr) {
76         DeleteArray(static_cast<char*>(entry->value));
77         RemoveEntry(entry);
78       }
79     }
80 
Move(Address from,Address to)81     void Move(Address from, Address to) {
82       if (from == to) return;
83       base::HashMap::Entry* from_entry = FindEntry(from);
84       DCHECK_NOT_NULL(from_entry);
85       void* value = from_entry->value;
86       RemoveEntry(from_entry);
87       base::HashMap::Entry* to_entry = FindOrCreateEntry(to);
88       DCHECK_NULL(to_entry->value);
89       to_entry->value = value;
90     }
91 
92    private:
CopyName(const char * name,int name_size)93     static char* CopyName(const char* name, int name_size) {
94       char* result = NewArray<char>(name_size + 1);
95       for (int i = 0; i < name_size; ++i) {
96         char c = name[i];
97         if (c == '\0') c = ' ';
98         result[i] = c;
99       }
100       result[name_size] = '\0';
101       return result;
102     }
103 
FindOrCreateEntry(Address code_address)104     base::HashMap::Entry* FindOrCreateEntry(Address code_address) {
105       return impl_.LookupOrInsert(reinterpret_cast<void*>(code_address),
106                                   ComputeAddressHash(code_address));
107     }
108 
FindEntry(Address code_address)109     base::HashMap::Entry* FindEntry(Address code_address) {
110       return impl_.Lookup(reinterpret_cast<void*>(code_address),
111                           ComputeAddressHash(code_address));
112     }
113 
RemoveEntry(base::HashMap::Entry * entry)114     void RemoveEntry(base::HashMap::Entry* entry) {
115       impl_.Remove(entry->key, entry->hash);
116     }
117 
118     base::HashMap impl_;
119   };
120 
LogRecordedBuffer(Handle<AbstractCode> code,MaybeHandle<SharedFunctionInfo>,const char * name,int length)121   void LogRecordedBuffer(Handle<AbstractCode> code,
122                          MaybeHandle<SharedFunctionInfo>, const char* name,
123                          int length) override {
124     address_to_name_map_.Insert(code->address(), name, length);
125   }
126 
LogRecordedBuffer(const wasm::WasmCode * code,const char * name,int length)127   void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
128                          int length) override {
129     UNREACHABLE();
130   }
131 
132   NameMap address_to_name_map_;
133 };
134 
135 class ObjectCacheIndexMap {
136  public:
ObjectCacheIndexMap(Heap * heap)137   explicit ObjectCacheIndexMap(Heap* heap) : map_(heap), next_index_(0) {}
138   ObjectCacheIndexMap(const ObjectCacheIndexMap&) = delete;
139   ObjectCacheIndexMap& operator=(const ObjectCacheIndexMap&) = delete;
140 
141   // If |obj| is in the map, immediately return true.  Otherwise add it to the
142   // map and return false. In either case set |*index_out| to the index
143   // associated with the map.
LookupOrInsert(Handle<HeapObject> obj,int * index_out)144   bool LookupOrInsert(Handle<HeapObject> obj, int* index_out) {
145     auto find_result = map_.FindOrInsert(obj);
146     if (!find_result.already_exists) {
147       *find_result.entry = next_index_++;
148     }
149     *index_out = *find_result.entry;
150     return find_result.already_exists;
151   }
152 
153  private:
154   DisallowHeapAllocation no_allocation_;
155 
156   IdentityMap<int, base::DefaultAllocationPolicy> map_;
157   int next_index_;
158 };
159 
160 class Serializer : public SerializerDeserializer {
161  public:
162   Serializer(Isolate* isolate, Snapshot::SerializerFlags flags);
~Serializer()163   ~Serializer() override { DCHECK_EQ(unresolved_forward_refs_, 0); }
164   Serializer(const Serializer&) = delete;
165   Serializer& operator=(const Serializer&) = delete;
166 
Payload()167   const std::vector<byte>* Payload() const { return sink_.data(); }
168 
ReferenceMapContains(Handle<HeapObject> o)169   bool ReferenceMapContains(Handle<HeapObject> o) {
170     return reference_map()->LookupReference(o) != nullptr;
171   }
172 
isolate()173   Isolate* isolate() const { return isolate_; }
174 
175   int TotalAllocationSize() const;
176 
177  protected:
178   using PendingObjectReferences = std::vector<int>*;
179 
180   class ObjectSerializer;
181   class RecursionScope {
182    public:
RecursionScope(Serializer * serializer)183     explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
184       serializer_->recursion_depth_++;
185     }
~RecursionScope()186     ~RecursionScope() { serializer_->recursion_depth_--; }
ExceedsMaximum()187     bool ExceedsMaximum() {
188       return serializer_->recursion_depth_ >= kMaxRecursionDepth;
189     }
190 
191    private:
192     static const int kMaxRecursionDepth = 32;
193     Serializer* serializer_;
194   };
195 
196   void SerializeDeferredObjects();
197   void SerializeObject(Handle<HeapObject> o);
198   virtual void SerializeObjectImpl(Handle<HeapObject> o) = 0;
199 
200   virtual bool MustBeDeferred(HeapObject object);
201 
202   void VisitRootPointers(Root root, const char* description,
203                          FullObjectSlot start, FullObjectSlot end) override;
204   void SerializeRootObject(FullObjectSlot slot);
205 
206   void PutRoot(RootIndex root_index);
207   void PutSmiRoot(FullObjectSlot slot);
208   void PutBackReference(Handle<HeapObject> object,
209                         SerializerReference reference);
210   void PutAttachedReference(SerializerReference reference);
211   void PutNextChunk(SnapshotSpace space);
212   void PutRepeat(int repeat_count);
213 
214   // Emit a marker noting that this slot is a forward reference to the an
215   // object which has not yet been serialized.
216   void PutPendingForwardReference(PendingObjectReferences& ref);
217   // Resolve the given previously registered forward reference to the current
218   // object.
219   void ResolvePendingForwardReference(int obj);
220 
221   // Returns true if the object was successfully serialized as a root.
222   bool SerializeRoot(Handle<HeapObject> obj);
223 
224   // Returns true if the object was successfully serialized as hot object.
225   bool SerializeHotObject(Handle<HeapObject> obj);
226 
227   // Returns true if the object was successfully serialized as back reference.
228   bool SerializeBackReference(Handle<HeapObject> obj);
229 
230   // Returns true if the object was successfully serialized as pending object.
231   bool SerializePendingObject(Handle<HeapObject> obj);
232 
233   // Returns true if the given heap object is a bytecode handler code object.
234   bool ObjectIsBytecodeHandler(Handle<HeapObject> obj) const;
235 
EncodeExternalReference(Address addr)236   ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) {
237     return external_reference_encoder_.Encode(addr);
238   }
TryEncodeExternalReference(Address addr)239   Maybe<ExternalReferenceEncoder::Value> TryEncodeExternalReference(
240       Address addr) {
241     return external_reference_encoder_.TryEncode(addr);
242   }
243 
244   // GetInt reads 4 bytes at once, requiring padding at the end.
245   // Use padding_offset to specify the space you want to use after padding.
246   void Pad(int padding_offset = 0);
247 
248   // We may not need the code address map for logging for every instance
249   // of the serializer.  Initialize it on demand.
250   void InitializeCodeAddressMap();
251 
252   Code CopyCode(Code code);
253 
QueueDeferredObject(Handle<HeapObject> obj)254   void QueueDeferredObject(Handle<HeapObject> obj) {
255     DCHECK_NULL(reference_map_.LookupReference(obj));
256     deferred_objects_.Push(*obj);
257   }
258 
259   // Register that the the given object shouldn't be immediately serialized, but
260   // will be serialized later and any references to it should be pending forward
261   // references.
262   void RegisterObjectIsPending(Handle<HeapObject> obj);
263 
264   // Resolve the given pending object reference with the current object.
265   void ResolvePendingObject(Handle<HeapObject> obj);
266 
267   void OutputStatistics(const char* name);
268 
269   void CountAllocation(Map map, int size, SnapshotSpace space);
270 
271 #ifdef DEBUG
PushStack(Handle<HeapObject> o)272   void PushStack(Handle<HeapObject> o) { stack_.Push(*o); }
PopStack()273   void PopStack() { stack_.Pop(); }
274   void PrintStack();
275   void PrintStack(std::ostream&);
276 #endif  // DEBUG
277 
reference_map()278   SerializerReferenceMap* reference_map() { return &reference_map_; }
root_index_map()279   const RootIndexMap* root_index_map() const { return &root_index_map_; }
280 
281   SnapshotByteSink sink_;  // Used directly by subclasses.
282 
allow_unknown_external_references_for_testing()283   bool allow_unknown_external_references_for_testing() const {
284     return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0;
285   }
allow_active_isolate_for_testing()286   bool allow_active_isolate_for_testing() const {
287     return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
288   }
289 
290  private:
291   // A circular queue of hot objects. This is added to in the same order as in
292   // Deserializer::HotObjectsList, but this stores the objects as an array of
293   // raw addresses that are considered strong roots. This allows objects to be
294   // added to the list without having to extend their handle's lifetime.
295   //
296   // We should never allow this class to return Handles to objects in the queue,
297   // as the object in the queue may change if kSize other objects are added to
298   // the queue during that Handle's lifetime.
299   class HotObjectsList {
300    public:
301     explicit HotObjectsList(Heap* heap);
302     ~HotObjectsList();
303     HotObjectsList(const HotObjectsList&) = delete;
304     HotObjectsList& operator=(const HotObjectsList&) = delete;
305 
Add(HeapObject object)306     void Add(HeapObject object) {
307       circular_queue_[index_] = object.ptr();
308       index_ = (index_ + 1) & kSizeMask;
309     }
310 
311     static const int kNotFound = -1;
312 
Find(HeapObject object)313     int Find(HeapObject object) {
314       DCHECK(!AllowGarbageCollection::IsAllowed());
315       for (int i = 0; i < kSize; i++) {
316         if (circular_queue_[i] == object.ptr()) {
317           return i;
318         }
319       }
320       return kNotFound;
321     }
322 
323    private:
324     static const int kSize = kHotObjectCount;
325     static const int kSizeMask = kSize - 1;
326     STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
327     Heap* heap_;
328     StrongRootsEntry* strong_roots_entry_;
329     Address circular_queue_[kSize] = {kNullAddress};
330     int index_ = 0;
331   };
332 
333   // Disallow GC during serialization.
334   // TODO(leszeks, v8:10815): Remove this constraint.
335   DISALLOW_HEAP_ALLOCATION(no_gc)
336 
337   Isolate* isolate_;
338   HotObjectsList hot_objects_;
339   SerializerReferenceMap reference_map_;
340   ExternalReferenceEncoder external_reference_encoder_;
341   RootIndexMap root_index_map_;
342   std::unique_ptr<CodeAddressMap> code_address_map_;
343   std::vector<byte> code_buffer_;
344   GlobalHandleVector<HeapObject>
345       deferred_objects_;  // To handle stack overflow.
346   int num_back_refs_ = 0;
347 
348   // Objects which have started being serialized, but haven't yet been allocated
349   // with the allocator, are considered "pending". References to them don't have
350   // an allocation to backref to, so instead they are registered as pending
351   // forward references, which are resolved once the object is allocated.
352   //
353   // Forward references are registered in a deterministic order, and can
354   // therefore be identified by an incrementing integer index, which is
355   // effectively an index into a vector of the currently registered forward
356   // refs. The references in this vector might not be resolved in order, so we
357   // can only clear it (and reset the indices) when there are no unresolved
358   // forward refs remaining.
359   int next_forward_ref_id_ = 0;
360   int unresolved_forward_refs_ = 0;
361   IdentityMap<PendingObjectReferences, base::DefaultAllocationPolicy>
362       forward_refs_per_pending_object_;
363 
364   // Used to keep track of the off-heap backing stores used by TypedArrays/
365   // ArrayBuffers. Note that the index begins at 1 and not 0, because when a
366   // TypedArray has an on-heap backing store, the backing_store pointer in the
367   // corresponding ArrayBuffer will be null, which makes it indistinguishable
368   // from index 0.
369   uint32_t seen_backing_stores_index_ = 1;
370 
371   int recursion_depth_ = 0;
372   const Snapshot::SerializerFlags flags_;
373 
374   size_t allocation_size_[kNumberOfSnapshotSpaces] = {0};
375 #ifdef OBJECT_PRINT
376   static constexpr int kInstanceTypes = LAST_TYPE + 1;
377   std::unique_ptr<int[]> instance_type_count_[kNumberOfSnapshotSpaces];
378   std::unique_ptr<size_t[]> instance_type_size_[kNumberOfSnapshotSpaces];
379 #endif  // OBJECT_PRINT
380 
381 #ifdef DEBUG
382   GlobalHandleVector<HeapObject> back_refs_;
383   GlobalHandleVector<HeapObject> stack_;
384 #endif  // DEBUG
385 };
386 
387 class RelocInfoIterator;
388 
389 class Serializer::ObjectSerializer : public ObjectVisitor {
390  public:
ObjectSerializer(Serializer * serializer,Handle<HeapObject> obj,SnapshotByteSink * sink)391   ObjectSerializer(Serializer* serializer, Handle<HeapObject> obj,
392                    SnapshotByteSink* sink)
393       : isolate_(serializer->isolate()),
394         serializer_(serializer),
395         object_(obj),
396         sink_(sink),
397         bytes_processed_so_far_(0) {
398 #ifdef DEBUG
399     serializer_->PushStack(obj);
400 #endif  // DEBUG
401   }
402   // NOLINTNEXTLINE (modernize-use-equals-default)
~ObjectSerializer()403   ~ObjectSerializer() override {
404 #ifdef DEBUG
405     serializer_->PopStack();
406 #endif  // DEBUG
407   }
408   void Serialize();
409   void SerializeObject();
410   void SerializeDeferred();
411   void VisitPointers(HeapObject host, ObjectSlot start,
412                      ObjectSlot end) override;
413   void VisitPointers(HeapObject host, MaybeObjectSlot start,
414                      MaybeObjectSlot end) override;
415   void VisitEmbeddedPointer(Code host, RelocInfo* target) override;
416   void VisitExternalReference(Foreign host, Address* p) override;
417   void VisitExternalReference(Code host, RelocInfo* rinfo) override;
418   void VisitInternalReference(Code host, RelocInfo* rinfo) override;
419   void VisitCodeTarget(Code host, RelocInfo* target) override;
420   void VisitRuntimeEntry(Code host, RelocInfo* reloc) override;
421   void VisitOffHeapTarget(Code host, RelocInfo* target) override;
422 
isolate()423   Isolate* isolate() { return isolate_; }
424 
425  private:
426   class RelocInfoObjectPreSerializer;
427 
428   void SerializePrologue(SnapshotSpace space, int size, Map map);
429 
430   // This function outputs or skips the raw data between the last pointer and
431   // up to the current position.
432   void SerializeContent(Map map, int size);
433   void OutputExternalReference(Address target, int target_size,
434                                bool sandboxify);
435   void OutputRawData(Address up_to);
436   void SerializeCode(Map map, int size);
437   uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
438   void SerializeJSTypedArray();
439   void SerializeJSArrayBuffer();
440   void SerializeExternalString();
441   void SerializeExternalStringAsSequentialString();
442 
443   Isolate* isolate_;
444   Serializer* serializer_;
445   Handle<HeapObject> object_;
446   SnapshotByteSink* sink_;
447   int bytes_processed_so_far_;
448 };
449 
450 }  // namespace internal
451 }  // namespace v8
452 
453 #endif  // V8_SNAPSHOT_SERIALIZER_H_
454