serializer.h 10.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_SNAPSHOT_SERIALIZER_H_
#define V8_SNAPSHOT_SERIALIZER_H_

#include "src/isolate.h"
#include "src/log.h"
#include "src/objects.h"
#include "src/snapshot/serializer-common.h"
#include "src/snapshot/snapshot-source-sink.h"

namespace v8 {
namespace internal {

class CodeAddressMap : public CodeEventLogger {
 public:
  explicit CodeAddressMap(Isolate* isolate) : isolate_(isolate) {
    isolate->logger()->addCodeEventListener(this);
  }

  ~CodeAddressMap() override {
    isolate_->logger()->removeCodeEventListener(this);
  }

  void CodeMoveEvent(AbstractCode* from, Address to) override {
    address_to_name_map_.Move(from->address(), to);
  }

  void CodeDisableOptEvent(AbstractCode* code,
                           SharedFunctionInfo* shared) override {}

  const char* Lookup(Address address) {
    return address_to_name_map_.Lookup(address);
  }

 private:
  class NameMap {
   public:
41
    NameMap() : impl_() {}
42 43

    ~NameMap() {
lpy's avatar
lpy committed
44 45
      for (base::HashMap::Entry* p = impl_.Start(); p != NULL;
           p = impl_.Next(p)) {
46 47 48 49 50
        DeleteArray(static_cast<const char*>(p->value));
      }
    }

    void Insert(Address code_address, const char* name, int name_size) {
lpy's avatar
lpy committed
51
      base::HashMap::Entry* entry = FindOrCreateEntry(code_address);
52 53 54 55 56 57
      if (entry->value == NULL) {
        entry->value = CopyName(name, name_size);
      }
    }

    const char* Lookup(Address code_address) {
lpy's avatar
lpy committed
58
      base::HashMap::Entry* entry = FindEntry(code_address);
59 60 61 62
      return (entry != NULL) ? static_cast<const char*>(entry->value) : NULL;
    }

    void Remove(Address code_address) {
lpy's avatar
lpy committed
63
      base::HashMap::Entry* entry = FindEntry(code_address);
64 65 66 67 68 69 70 71
      if (entry != NULL) {
        DeleteArray(static_cast<char*>(entry->value));
        RemoveEntry(entry);
      }
    }

    void Move(Address from, Address to) {
      if (from == to) return;
lpy's avatar
lpy committed
72
      base::HashMap::Entry* from_entry = FindEntry(from);
73 74 75
      DCHECK(from_entry != NULL);
      void* value = from_entry->value;
      RemoveEntry(from_entry);
lpy's avatar
lpy committed
76
      base::HashMap::Entry* to_entry = FindOrCreateEntry(to);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
      DCHECK(to_entry->value == NULL);
      to_entry->value = value;
    }

   private:
    static char* CopyName(const char* name, int name_size) {
      char* result = NewArray<char>(name_size + 1);
      for (int i = 0; i < name_size; ++i) {
        char c = name[i];
        if (c == '\0') c = ' ';
        result[i] = c;
      }
      result[name_size] = '\0';
      return result;
    }

lpy's avatar
lpy committed
93
    base::HashMap::Entry* FindOrCreateEntry(Address code_address) {
94 95 96 97
      return impl_.LookupOrInsert(code_address,
                                  ComputePointerHash(code_address));
    }

lpy's avatar
lpy committed
98
    base::HashMap::Entry* FindEntry(Address code_address) {
99 100 101
      return impl_.Lookup(code_address, ComputePointerHash(code_address));
    }

lpy's avatar
lpy committed
102
    void RemoveEntry(base::HashMap::Entry* entry) {
103 104 105
      impl_.Remove(entry->key, entry->hash);
    }

lpy's avatar
lpy committed
106
    base::HashMap impl_;
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

    DISALLOW_COPY_AND_ASSIGN(NameMap);
  };

  void LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
                         const char* name, int length) override {
    address_to_name_map_.Insert(code->address(), name, length);
  }

  NameMap address_to_name_map_;
  Isolate* isolate_;
};

// There can be only one serializer per V8 process.
class Serializer : public SerializerDeserializer {
 public:
123
  explicit Serializer(Isolate* isolate);
124 125 126 127 128 129 130 131
  ~Serializer() override;

  void EncodeReservations(List<SerializedData::Reservation>* out) const;

  void SerializeDeferredObjects();

  Isolate* isolate() const { return isolate_; }

132
  SerializerReferenceMap* reference_map() { return &reference_map_; }
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  RootIndexMap* root_index_map() { return &root_index_map_; }

#ifdef OBJECT_PRINT
  void CountInstanceType(Map* map, int size);
#endif  // OBJECT_PRINT

 protected:
  class ObjectSerializer;
  class RecursionScope {
   public:
    explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
      serializer_->recursion_depth_++;
    }
    ~RecursionScope() { serializer_->recursion_depth_--; }
    bool ExceedsMaximum() {
      return serializer_->recursion_depth_ >= kMaxRecursionDepth;
    }

   private:
    static const int kMaxRecursionDepth = 32;
    Serializer* serializer_;
  };

  virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
                               WhereToPoint where_to_point, int skip) = 0;

159 160
  void VisitPointers(Object** start, Object** end) override;

161 162 163
  void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
               int skip);

164 165
  void PutSmi(Smi* smi);

166 167 168 169
  void PutBackReference(HeapObject* object, SerializerReference reference);

  void PutAttachedReference(SerializerReference reference,
                            HowToCode how_to_code, WhereToPoint where_to_point);
170 171 172 173

  // Emit alignment prefix if necessary, return required padding space in bytes.
  int PutAlignmentPrefix(HeapObject* object);

174 175 176 177 178 179 180
  // Returns true if the object was successfully serialized as hot object.
  bool SerializeHotObject(HeapObject* obj, HowToCode how_to_code,
                          WhereToPoint where_to_point, int skip);

  // Returns true if the object was successfully serialized as back reference.
  bool SerializeBackReference(HeapObject* obj, HowToCode how_to_code,
                              WhereToPoint where_to_point, int skip);
181 182 183

  inline void FlushSkip(int skip) {
    if (skip != 0) {
184 185
      sink_.Put(kSkip, "SkipFromSerializeObject");
      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);
195 196 197 198
  int EncodeExternalReference(Address addr) {
    return external_reference_encoder_.Encode(addr);
  }

199 200
  bool HasNotExceededFirstPageOfEachSpace();

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
  // GetInt reads 4 bytes at once, requiring padding at the end.
  void Pad();

  // We may not need the code address map for logging for every instance
  // of the serializer.  Initialize it on demand.
  void InitializeCodeAddressMap();

  Code* CopyCode(Code* code);

  inline uint32_t max_chunk_size(int space) const {
    DCHECK_LE(0, space);
    DCHECK_LT(space, kNumberOfSpaces);
    return max_chunk_size_[space];
  }

216
  const SnapshotByteSink* sink() const { return &sink_; }
217 218

  void QueueDeferredObject(HeapObject* obj) {
219
    DCHECK(reference_map_.Lookup(obj).is_back_reference());
220 221 222 223 224 225 226
    deferred_objects_.Add(obj);
  }

  void OutputStatistics(const char* name);

  Isolate* isolate_;

227
  SnapshotByteSink sink_;
228 229
  ExternalReferenceEncoder external_reference_encoder_;

230
  SerializerReferenceMap reference_map_;
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  RootIndexMap root_index_map_;

  int recursion_depth_;

  friend class Deserializer;
  friend class ObjectSerializer;
  friend class RecursionScope;
  friend class SnapshotData;

 private:
  CodeAddressMap* code_address_map_;
  // Objects from the same space are put into chunks for bulk-allocation
  // when deserializing. We have to make sure that each chunk fits into a
  // page. So we track the chunk size in pending_chunk_ of a space, but
  // when it exceeds a page, we complete the current chunk and start a new one.
  uint32_t pending_chunk_[kNumberOfPreallocatedSpaces];
  List<uint32_t> completed_chunks_[kNumberOfPreallocatedSpaces];
  uint32_t max_chunk_size_[kNumberOfPreallocatedSpaces];
249 250
  // Number of maps that we need to allocate.
  uint32_t num_maps_;
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

  // We map serialized large objects to indexes for back-referencing.
  uint32_t large_objects_total_size_;
  uint32_t seen_large_objects_index_;

  List<byte> code_buffer_;

  // To handle stack overflow.
  List<HeapObject*> deferred_objects_;

#ifdef OBJECT_PRINT
  static const int kInstanceTypes = 256;
  int* instance_type_count_;
  size_t* instance_type_size_;
#endif  // OBJECT_PRINT

  DISALLOW_COPY_AND_ASSIGN(Serializer);
};

class Serializer::ObjectSerializer : public ObjectVisitor {
 public:
  ObjectSerializer(Serializer* serializer, HeapObject* obj,
                   SnapshotByteSink* sink, HowToCode how_to_code,
                   WhereToPoint where_to_point)
      : serializer_(serializer),
        object_(obj),
        sink_(sink),
        reference_representation_(how_to_code + where_to_point),
        bytes_processed_so_far_(0),
        code_has_been_output_(false) {}
  ~ObjectSerializer() override {}
  void Serialize();
  void SerializeDeferred();
  void VisitPointers(Object** start, Object** end) override;
  void VisitEmbeddedPointer(RelocInfo* target) override;
  void VisitExternalReference(Address* p) override;
  void VisitExternalReference(RelocInfo* rinfo) override;
  void VisitInternalReference(RelocInfo* rinfo) override;
  void VisitCodeTarget(RelocInfo* target) override;
  void VisitCodeEntry(Address entry_address) override;
  void VisitCell(RelocInfo* rinfo) override;
  void VisitRuntimeEntry(RelocInfo* reloc) override;
  // Used for seralizing the external strings that hold the natives source.
  void VisitExternalOneByteString(
      v8::String::ExternalOneByteStringResource** resource) override;
  // We can't serialize a heap with external two byte strings.
  void VisitExternalTwoByteString(
      v8::String::ExternalStringResource** resource) override {
    UNREACHABLE();
  }

 private:
  void SerializePrologue(AllocationSpace space, int size, Map* map);

  bool SerializeExternalNativeSourceString(
      int builtin_count,
      v8::String::ExternalOneByteStringResource** resource_pointer,
      FixedArray* source_cache, int resource_index);

  enum ReturnSkip { kCanReturnSkipInsteadOfSkipping, kIgnoringReturn };
  // This function outputs or skips the raw data between the last pointer and
  // up to the current position.  It optionally can just return the number of
  // bytes to skip instead of performing a skip instruction, in case the skip
  // can be merged into the next instruction.
  int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
  // External strings are serialized in a way to resemble sequential strings.
  void SerializeExternalString();

  Address PrepareCode();

  Serializer* serializer_;
  HeapObject* object_;
  SnapshotByteSink* sink_;
  int reference_representation_;
  int bytes_processed_so_far_;
  bool code_has_been_output_;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_SNAPSHOT_SERIALIZER_H_