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