Home | History | Annotate | Download | only in snapshot
      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_COMMON_H_
      6 #define V8_SNAPSHOT_SERIALIZER_COMMON_H_
      7 
      8 #include "src/address-map.h"
      9 #include "src/base/bits.h"
     10 #include "src/external-reference-table.h"
     11 #include "src/globals.h"
     12 #include "src/snapshot/references.h"
     13 #include "src/v8memory.h"
     14 #include "src/visitors.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 class CallHandlerInfo;
     20 class Isolate;
     21 
     22 class ExternalReferenceEncoder {
     23  public:
     24   class Value {
     25    public:
     26     explicit Value(uint32_t raw) : value_(raw) {}
     27     Value() : value_(0) {}
     28     static uint32_t Encode(uint32_t index, bool is_from_api) {
     29       return Index::encode(index) | IsFromAPI::encode(is_from_api);
     30     }
     31 
     32     bool is_from_api() const { return IsFromAPI::decode(value_); }
     33     uint32_t index() const { return Index::decode(value_); }
     34 
     35    private:
     36     class Index : public BitField<uint32_t, 0, 31> {};
     37     class IsFromAPI : public BitField<bool, 31, 1> {};
     38     uint32_t value_;
     39   };
     40 
     41   explicit ExternalReferenceEncoder(Isolate* isolate);
     42   ~ExternalReferenceEncoder();
     43 
     44   Value Encode(Address key);
     45   Maybe<Value> TryEncode(Address key);
     46 
     47   const char* NameOfAddress(Isolate* isolate, Address address) const;
     48 
     49  private:
     50   AddressToIndexHashMap* map_;
     51 
     52 #ifdef DEBUG
     53   std::vector<int> count_;
     54   const intptr_t* api_references_;
     55 #endif  // DEBUG
     56 
     57   DISALLOW_COPY_AND_ASSIGN(ExternalReferenceEncoder);
     58 };
     59 
     60 class HotObjectsList {
     61  public:
     62   HotObjectsList() : index_(0) {
     63     for (int i = 0; i < kSize; i++) circular_queue_[i] = nullptr;
     64   }
     65 
     66   void Add(HeapObject* object) {
     67     DCHECK(!AllowHeapAllocation::IsAllowed());
     68     circular_queue_[index_] = object;
     69     index_ = (index_ + 1) & kSizeMask;
     70   }
     71 
     72   HeapObject* Get(int index) {
     73     DCHECK(!AllowHeapAllocation::IsAllowed());
     74     DCHECK_NOT_NULL(circular_queue_[index]);
     75     return circular_queue_[index];
     76   }
     77 
     78   static const int kNotFound = -1;
     79 
     80   int Find(HeapObject* object) {
     81     DCHECK(!AllowHeapAllocation::IsAllowed());
     82     for (int i = 0; i < kSize; i++) {
     83       if (circular_queue_[i] == object) return i;
     84     }
     85     return kNotFound;
     86   }
     87 
     88   static const int kSize = 8;
     89 
     90  private:
     91   static_assert(base::bits::IsPowerOfTwo(kSize), "kSize must be power of two");
     92   static const int kSizeMask = kSize - 1;
     93   HeapObject* circular_queue_[kSize];
     94   int index_;
     95 
     96   DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
     97 };
     98 
     99 // The Serializer/Deserializer class is a common superclass for Serializer and
    100 // Deserializer which is used to store common constants and methods used by
    101 // both.
    102 class SerializerDeserializer : public RootVisitor {
    103  public:
    104   static void Iterate(Isolate* isolate, RootVisitor* visitor);
    105 
    106   // No reservation for large object space necessary.
    107   // We also handle map space differenly.
    108   STATIC_ASSERT(MAP_SPACE == CODE_SPACE + 1);
    109 
    110   // We do not support young generation large objects.
    111   STATIC_ASSERT(LAST_SPACE == NEW_LO_SPACE);
    112   STATIC_ASSERT(LAST_SPACE - 1 == LO_SPACE);
    113   static const int kNumberOfPreallocatedSpaces = CODE_SPACE + 1;
    114   static const int kNumberOfSpaces = LO_SPACE + 1;
    115 
    116  protected:
    117   static bool CanBeDeferred(HeapObject* o);
    118 
    119   void RestoreExternalReferenceRedirectors(
    120       const std::vector<AccessorInfo*>& accessor_infos);
    121   void RestoreExternalReferenceRedirectors(
    122       const std::vector<CallHandlerInfo*>& call_handler_infos);
    123 
    124 #define UNUSED_SERIALIZER_BYTE_CODES(V) \
    125   V(0x18)                               \
    126   V(0x3d)                               \
    127   V(0x3e)                               \
    128   V(0x3f)                               \
    129   V(0x58)                               \
    130   V(0x59)                               \
    131   V(0x5a)                               \
    132   V(0x5b)                               \
    133   V(0x5c)                               \
    134   V(0x5d)                               \
    135   V(0x5e)                               \
    136   V(0x5f)                               \
    137   V(0x67)                               \
    138   V(0x76)                               \
    139   V(0x78)                               \
    140   V(0x79)                               \
    141   V(0x7a)                               \
    142   V(0x7b)                               \
    143   V(0x7c)                               \
    144   V(0x7d)
    145 
    146   // ---------- byte code range 0x00..0x7f ----------
    147   // Byte codes in this range represent Where, HowToCode and WhereToPoint.
    148   // Where the pointed-to object can be found:
    149   // The static assert below will trigger when the number of preallocated spaces
    150   // changed. If that happens, update the bytecode ranges in the comments below.
    151   STATIC_ASSERT(6 == kNumberOfSpaces);
    152   enum Where {
    153     // 0x00..0x05  Allocate new object, in specified space.
    154     kNewObject = 0x00,
    155     // 0x08..0x0d  Reference to previous object from space.
    156     kBackref = 0x08,
    157     // 0x10..0x15  Reference to previous object from space after skip.
    158     kBackrefWithSkip = 0x10,
    159 
    160     // 0x06        Object in the partial snapshot cache.
    161     kPartialSnapshotCache = 0x06,
    162     // 0x07        External reference referenced by id.
    163     kExternalReference = 0x07,
    164 
    165     // 0x0e        Builtin code referenced by index.
    166     kBuiltin = 0x0e,
    167     // 0x16       Root array item.
    168     kRootArray = 0x16,
    169     // 0x17        Object provided in the attached list.
    170     kAttachedReference = 0x17,
    171 
    172     // 0x0f        Misc, see below (incl. 0x2f, 0x4f, 0x6f).
    173     // 0x18..0x1f  Misc, see below (incl. 0x38..0x3f, 0x58..0x5f, 0x78..0x7f).
    174   };
    175 
    176   static const int kWhereMask = 0x1f;
    177   static const int kSpaceMask = 7;
    178   STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
    179 
    180   // How to code the pointer to the object.
    181   enum HowToCode {
    182     // Straight pointer.
    183     kPlain = 0,
    184     // A pointer inlined in code. What this means depends on the architecture.
    185     kFromCode = 0x20
    186   };
    187 
    188   static const int kHowToCodeMask = 0x20;
    189 
    190   // Where to point within the object.
    191   enum WhereToPoint {
    192     // Points to start of object
    193     kStartOfObject = 0,
    194     // Points to instruction in code object or payload of cell.
    195     kInnerPointer = 0x40
    196   };
    197 
    198   static const int kWhereToPointMask = 0x40;
    199 
    200   // ---------- Misc ----------
    201   // Skip.
    202   static const int kSkip = 0x0f;
    203   // Do nothing, used for padding.
    204   static const int kNop = 0x2f;
    205   // Move to next reserved chunk.
    206   static const int kNextChunk = 0x4f;
    207   // Deferring object content.
    208   static const int kDeferred = 0x6f;
    209   // Alignment prefixes 0x19..0x1b
    210   static const int kAlignmentPrefix = 0x19;
    211   // A tag emitted at strategic points in the snapshot to delineate sections.
    212   // If the deserializer does not find these at the expected moments then it
    213   // is an indication that the snapshot and the VM do not fit together.
    214   // Examine the build process for architecture, version or configuration
    215   // mismatches.
    216   static const int kSynchronize = 0x1c;
    217   // Repeats of variable length.
    218   static const int kVariableRepeat = 0x1d;
    219   // Raw data of variable length.
    220 
    221   // Used for embedder-allocated backing stores for TypedArrays.
    222   static const int kOffHeapBackingStore = 0x1e;
    223 
    224   // Used for embedder-provided serialization data for embedder fields.
    225   static const int kEmbedderFieldsData = 0x1f;
    226 
    227   // Used to encode external referenced provided through the API.
    228   static const int kApiReference = 0x38;
    229 
    230   static const int kVariableRawCode = 0x39;
    231   static const int kVariableRawData = 0x3a;
    232 
    233   static const int kInternalReference = 0x3b;
    234   static const int kInternalReferenceEncoded = 0x3c;
    235 
    236   // In-place weak references
    237   static const int kWeakPrefix = 0x7e;
    238 
    239   // Encodes an off-heap instruction stream target.
    240   static const int kOffHeapTarget = 0x7f;
    241 
    242   // ---------- byte code range 0x80..0xff ----------
    243   // First 32 root array items.
    244   static const int kNumberOfRootArrayConstants = 0x20;
    245   // 0x80..0x9f
    246   static const int kRootArrayConstants = 0x80;
    247   // 0xa0..0xbf
    248   static const int kRootArrayConstantsWithSkip = 0xa0;
    249   static const int kRootArrayConstantsMask = 0x1f;
    250 
    251   // 32 common raw data lengths.
    252   static const int kNumberOfFixedRawData = 0x20;
    253   // 0xc0..0xdf
    254   static const int kFixedRawData = 0xc0;
    255   static const int kOnePointerRawData = kFixedRawData;
    256   static const int kFixedRawDataStart = kFixedRawData - 1;
    257 
    258   // 16 repeats lengths.
    259   static const int kNumberOfFixedRepeat = 0x10;
    260   // 0xe0..0xef
    261   static const int kFixedRepeat = 0xe0;
    262   static const int kFixedRepeatStart = kFixedRepeat - 1;
    263 
    264   // 8 hot (recently seen or back-referenced) objects with optional skip.
    265   static const int kNumberOfHotObjects = 8;
    266   STATIC_ASSERT(kNumberOfHotObjects == HotObjectsList::kSize);
    267   // 0xf0..0xf7
    268   static const int kHotObject = 0xf0;
    269   // 0xf8..0xff
    270   static const int kHotObjectWithSkip = 0xf8;
    271   static const int kHotObjectMask = 0x07;
    272 
    273   // ---------- special values ----------
    274   static const int kAnyOldSpace = -1;
    275 
    276   // Sentinel after a new object to indicate that double alignment is needed.
    277   static const int kDoubleAlignmentSentinel = 0;
    278 
    279   // ---------- member variable ----------
    280   HotObjectsList hot_objects_;
    281 };
    282 
    283 class SerializedData {
    284  public:
    285   class Reservation {
    286    public:
    287     Reservation() : reservation_(0) {}
    288     explicit Reservation(uint32_t size)
    289         : reservation_(ChunkSizeBits::encode(size)) {}
    290 
    291     uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); }
    292     bool is_last() const { return IsLastChunkBits::decode(reservation_); }
    293 
    294     void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); }
    295 
    296    private:
    297     uint32_t reservation_;
    298   };
    299 
    300   SerializedData(byte* data, int size)
    301       : data_(data), size_(size), owns_data_(false) {}
    302   SerializedData() : data_(nullptr), size_(0), owns_data_(false) {}
    303   SerializedData(SerializedData&& other) V8_NOEXCEPT
    304       : data_(other.data_),
    305         size_(other.size_),
    306         owns_data_(other.owns_data_) {
    307     // Ensure |other| will not attempt to destroy our data in destructor.
    308     other.owns_data_ = false;
    309   }
    310 
    311   virtual ~SerializedData() {
    312     if (owns_data_) DeleteArray<byte>(data_);
    313   }
    314 
    315   uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
    316 
    317   class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
    318   class IsLastChunkBits : public BitField<bool, 31, 1> {};
    319 
    320   static uint32_t ComputeMagicNumber(ExternalReferenceTable* table) {
    321     uint32_t external_refs = table->size();
    322     return 0xC0DE0000 ^ external_refs;
    323   }
    324 
    325   static const uint32_t kMagicNumberOffset = 0;
    326 
    327  protected:
    328   void SetHeaderValue(uint32_t offset, uint32_t value) {
    329     WriteLittleEndianValue(reinterpret_cast<Address>(data_) + offset, value);
    330   }
    331 
    332   uint32_t GetHeaderValue(uint32_t offset) const {
    333     return ReadLittleEndianValue<uint32_t>(reinterpret_cast<Address>(data_) +
    334                                            offset);
    335   }
    336 
    337   void AllocateData(uint32_t size);
    338 
    339   static uint32_t ComputeMagicNumber(Isolate* isolate);
    340 
    341   void SetMagicNumber(Isolate* isolate) {
    342     SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate));
    343   }
    344 
    345   byte* data_;
    346   uint32_t size_;
    347   bool owns_data_;
    348 
    349  private:
    350   DISALLOW_COPY_AND_ASSIGN(SerializedData);
    351 };
    352 
    353 }  // namespace internal
    354 }  // namespace v8
    355 
    356 #endif  // V8_SNAPSHOT_SERIALIZER_COMMON_H_
    357