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