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/instruction-stream.h" 11 #include "src/isolate.h" 12 #include "src/log.h" 13 #include "src/objects.h" 14 #include "src/snapshot/default-serializer-allocator.h" 15 #include "src/snapshot/serializer-common.h" 16 #include "src/snapshot/snapshot-source-sink.h" 17 18 namespace v8 { 19 namespace internal { 20 21 class CodeAddressMap : public CodeEventLogger { 22 public: CodeAddressMap(Isolate * isolate)23 explicit CodeAddressMap(Isolate* isolate) : CodeEventLogger(isolate) { 24 isolate->logger()->AddCodeEventListener(this); 25 } 26 ~CodeAddressMap()27 ~CodeAddressMap() override { 28 isolate_->logger()->RemoveCodeEventListener(this); 29 } 30 CodeMoveEvent(AbstractCode * from,AbstractCode * to)31 void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override { 32 address_to_name_map_.Move(from->address(), to->address()); 33 } 34 CodeDisableOptEvent(AbstractCode * code,SharedFunctionInfo * shared)35 void CodeDisableOptEvent(AbstractCode* code, 36 SharedFunctionInfo* shared) override {} 37 Lookup(Address address)38 const char* Lookup(Address address) { 39 return address_to_name_map_.Lookup(address); 40 } 41 42 private: 43 class NameMap { 44 public: NameMap()45 NameMap() : impl_() {} 46 ~NameMap()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 Insert(Address code_address,const char * name,int name_size)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 Lookup(Address code_address)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 Remove(Address code_address)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 Move(Address from,Address to)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: CopyName(const char * name,int name_size)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 FindOrCreateEntry(Address code_address)98 base::HashMap::Entry* FindOrCreateEntry(Address code_address) { 99 return impl_.LookupOrInsert(reinterpret_cast<void*>(code_address), 100 ComputeAddressHash(code_address)); 101 } 102 FindEntry(Address code_address)103 base::HashMap::Entry* FindEntry(Address code_address) { 104 return impl_.Lookup(reinterpret_cast<void*>(code_address), 105 ComputeAddressHash(code_address)); 106 } 107 RemoveEntry(base::HashMap::Entry * entry)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 LogRecordedBuffer(AbstractCode * code,SharedFunctionInfo *,const char * name,int length)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 LogRecordedBuffer(const wasm::WasmCode * code,const char * name,int length)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 130 template <class AllocatorT = DefaultSerializerAllocator> 131 class Serializer : public SerializerDeserializer { 132 public: 133 explicit Serializer(Isolate* isolate); 134 ~Serializer() override; 135 EncodeReservations()136 std::vector<SerializedData::Reservation> EncodeReservations() const { 137 return allocator_.EncodeReservations(); 138 } 139 Payload()140 const std::vector<byte>* Payload() const { return sink_.data(); } 141 ReferenceMapContains(HeapObject * o)142 bool ReferenceMapContains(HeapObject* o) { 143 return reference_map()->LookupReference(o).is_valid(); 144 } 145 isolate()146 Isolate* isolate() const { return isolate_; } 147 148 protected: 149 class ObjectSerializer; 150 class RecursionScope { 151 public: RecursionScope(Serializer * serializer)152 explicit RecursionScope(Serializer* serializer) : serializer_(serializer) { 153 serializer_->recursion_depth_++; 154 } ~RecursionScope()155 ~RecursionScope() { serializer_->recursion_depth_--; } ExceedsMaximum()156 bool ExceedsMaximum() { 157 return serializer_->recursion_depth_ >= kMaxRecursionDepth; 158 } 159 160 private: 161 static const int kMaxRecursionDepth = 32; 162 Serializer* serializer_; 163 }; 164 165 void SerializeDeferredObjects(); 166 virtual void SerializeObject(HeapObject* o, HowToCode how_to_code, 167 WhereToPoint where_to_point, int skip) = 0; 168 169 virtual bool MustBeDeferred(HeapObject* object); 170 171 void VisitRootPointers(Root root, const char* description, Object** start, 172 Object** end) override; 173 void SerializeRootObject(Object* object); 174 175 void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where, 176 int skip); 177 void PutSmi(Smi* smi); 178 void PutBackReference(HeapObject* object, SerializerReference reference); 179 void PutAttachedReference(SerializerReference reference, 180 HowToCode how_to_code, WhereToPoint where_to_point); 181 // Emit alignment prefix if necessary, return required padding space in bytes. 182 int PutAlignmentPrefix(HeapObject* object); 183 void PutNextChunk(int space); 184 185 // Returns true if the object was successfully serialized as hot object. 186 bool SerializeHotObject(HeapObject* obj, HowToCode how_to_code, 187 WhereToPoint where_to_point, int skip); 188 189 // Returns true if the object was successfully serialized as back reference. 190 bool SerializeBackReference(HeapObject* obj, HowToCode how_to_code, 191 WhereToPoint where_to_point, int skip); 192 193 // Returns true if the object was successfully serialized as a builtin 194 // reference. 195 bool SerializeBuiltinReference(HeapObject* obj, HowToCode how_to_code, 196 WhereToPoint where_to_point, int skip); 197 198 // Returns true if the given heap object is a bytecode handler code object. 199 bool ObjectIsBytecodeHandler(HeapObject* obj) const; 200 FlushSkip(int skip)201 inline void FlushSkip(int skip) { 202 if (skip != 0) { 203 sink_.Put(kSkip, "SkipFromSerializeObject"); 204 sink_.PutInt(skip, "SkipDistanceFromSerializeObject"); 205 } 206 } 207 EncodeExternalReference(Address addr)208 ExternalReferenceEncoder::Value EncodeExternalReference(Address addr) { 209 return external_reference_encoder_.Encode(addr); 210 } 211 212 // GetInt reads 4 bytes at once, requiring padding at the end. 213 void Pad(); 214 215 // We may not need the code address map for logging for every instance 216 // of the serializer. Initialize it on demand. 217 void InitializeCodeAddressMap(); 218 219 Code* CopyCode(Code* code); 220 QueueDeferredObject(HeapObject * obj)221 void QueueDeferredObject(HeapObject* obj) { 222 DCHECK(reference_map_.LookupReference(obj).is_back_reference()); 223 deferred_objects_.push_back(obj); 224 } 225 226 void OutputStatistics(const char* name); 227 228 #ifdef OBJECT_PRINT 229 void CountInstanceType(Map* map, int size, AllocationSpace space); 230 #endif // OBJECT_PRINT 231 232 #ifdef DEBUG PushStack(HeapObject * o)233 void PushStack(HeapObject* o) { stack_.push_back(o); } PopStack()234 void PopStack() { stack_.pop_back(); } 235 void PrintStack(); 236 #endif // DEBUG 237 reference_map()238 SerializerReferenceMap* reference_map() { return &reference_map_; } root_index_map()239 RootIndexMap* root_index_map() { return &root_index_map_; } allocator()240 AllocatorT* allocator() { return &allocator_; } 241 242 SnapshotByteSink sink_; // Used directly by subclasses. 243 244 private: 245 Isolate* isolate_; 246 SerializerReferenceMap reference_map_; 247 ExternalReferenceEncoder external_reference_encoder_; 248 RootIndexMap root_index_map_; 249 CodeAddressMap* code_address_map_ = nullptr; 250 std::vector<byte> code_buffer_; 251 std::vector<HeapObject*> deferred_objects_; // To handle stack overflow. 252 int recursion_depth_ = 0; 253 AllocatorT allocator_; 254 255 #ifdef OBJECT_PRINT 256 static const int kInstanceTypes = LAST_TYPE + 1; 257 int* instance_type_count_[LAST_SPACE]; 258 size_t* instance_type_size_[LAST_SPACE]; 259 #endif // OBJECT_PRINT 260 261 #ifdef DEBUG 262 std::vector<HeapObject*> stack_; 263 #endif // DEBUG 264 265 friend class DefaultSerializerAllocator; 266 267 DISALLOW_COPY_AND_ASSIGN(Serializer); 268 }; 269 270 class RelocInfoIterator; 271 272 template <class AllocatorT> 273 class Serializer<AllocatorT>::ObjectSerializer : public ObjectVisitor { 274 public: ObjectSerializer(Serializer * serializer,HeapObject * obj,SnapshotByteSink * sink,HowToCode how_to_code,WhereToPoint where_to_point)275 ObjectSerializer(Serializer* serializer, HeapObject* obj, 276 SnapshotByteSink* sink, HowToCode how_to_code, 277 WhereToPoint where_to_point) 278 : serializer_(serializer), 279 object_(obj), 280 sink_(sink), 281 reference_representation_(how_to_code + where_to_point), 282 bytes_processed_so_far_(0) { 283 #ifdef DEBUG 284 serializer_->PushStack(obj); 285 #endif // DEBUG 286 } ~ObjectSerializer()287 ~ObjectSerializer() override { 288 #ifdef DEBUG 289 serializer_->PopStack(); 290 #endif // DEBUG 291 } 292 void Serialize(); 293 void SerializeObject(); 294 void SerializeDeferred(); 295 void VisitPointers(HeapObject* host, Object** start, Object** end) override; 296 void VisitPointers(HeapObject* host, MaybeObject** start, 297 MaybeObject** end) override; 298 void VisitEmbeddedPointer(Code* host, RelocInfo* target) override; 299 void VisitExternalReference(Foreign* host, Address* p) override; 300 void VisitExternalReference(Code* host, RelocInfo* rinfo) override; 301 void VisitInternalReference(Code* host, RelocInfo* rinfo) override; 302 void VisitCodeTarget(Code* host, RelocInfo* target) override; 303 void VisitRuntimeEntry(Code* host, RelocInfo* reloc) override; 304 void VisitOffHeapTarget(Code* host, RelocInfo* target) override; 305 // Relocation info needs to be visited sorted by target_address_address. 306 void VisitRelocInfo(RelocIterator* it) override; 307 308 private: 309 void SerializePrologue(AllocationSpace space, int size, Map* map); 310 311 // This function outputs or skips the raw data between the last pointer and 312 // up to the current position. 313 void SerializeContent(Map* map, int size); 314 void OutputRawData(Address up_to); 315 void OutputCode(int size); 316 int SkipTo(Address to); 317 int32_t SerializeBackingStore(void* backing_store, int32_t byte_length); 318 void SerializeJSTypedArray(); 319 void SerializeJSArrayBuffer(); 320 void SerializeExternalString(); 321 void SerializeExternalStringAsSequentialString(); 322 323 Serializer* serializer_; 324 HeapObject* object_; 325 SnapshotByteSink* sink_; 326 std::map<void*, Smi*> backing_stores; 327 int reference_representation_; 328 int bytes_processed_so_far_; 329 }; 330 331 } // namespace internal 332 } // namespace v8 333 334 #endif // V8_SNAPSHOT_SERIALIZER_H_ 335