Line data Source code
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/msan.h"
13 : #include "src/snapshot/references.h"
14 : #include "src/v8memory.h"
15 : #include "src/visitors.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : class CallHandlerInfo;
21 : class Isolate;
22 :
23 : class ExternalReferenceEncoder {
24 : public:
25 : class Value {
26 : public:
27 : explicit Value(uint32_t raw) : value_(raw) {}
28 : Value() : value_(0) {}
29 : static uint32_t Encode(uint32_t index, bool is_from_api) {
30 150 : return Index::encode(index) | IsFromAPI::encode(is_from_api);
31 : }
32 :
33 : bool is_from_api() const { return IsFromAPI::decode(value_); }
34 : uint32_t index() const { return Index::decode(value_); }
35 :
36 : private:
37 : class Index : public BitField<uint32_t, 0, 31> {};
38 : class IsFromAPI : public BitField<bool, 31, 1> {};
39 : uint32_t value_;
40 : };
41 :
42 : explicit ExternalReferenceEncoder(Isolate* isolate);
43 : ~ExternalReferenceEncoder(); // NOLINT (modernize-use-equals-default)
44 :
45 : Value Encode(Address key);
46 : Maybe<Value> TryEncode(Address key);
47 :
48 : const char* NameOfAddress(Isolate* isolate, Address address) const;
49 :
50 : private:
51 : AddressToIndexHashMap* map_;
52 :
53 : #ifdef DEBUG
54 : std::vector<int> count_;
55 : const intptr_t* api_references_;
56 : #endif // DEBUG
57 :
58 : DISALLOW_COPY_AND_ASSIGN(ExternalReferenceEncoder);
59 : };
60 :
61 : class HotObjectsList {
62 : public:
63 1968957 : HotObjectsList() : index_(0) {}
64 :
65 : void Add(HeapObject object) {
66 : DCHECK(!AllowHeapAllocation::IsAllowed());
67 391790365 : circular_queue_[index_] = object;
68 391790365 : index_ = (index_ + 1) & kSizeMask;
69 : }
70 :
71 : HeapObject Get(int index) {
72 : DCHECK(!AllowHeapAllocation::IsAllowed());
73 : DCHECK(!circular_queue_[index].is_null());
74 506144897 : return circular_queue_[index];
75 : }
76 :
77 : static const int kNotFound = -1;
78 :
79 : int Find(HeapObject object) {
80 : DCHECK(!AllowHeapAllocation::IsAllowed());
81 60148873 : for (int i = 0; i < kSize; i++) {
82 124640288 : 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 437548 : 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 :
109 : // We do not support young generation large objects and large code objects.
110 : STATIC_ASSERT(LAST_SPACE == NEW_LO_SPACE);
111 : STATIC_ASSERT(LAST_SPACE - 2 == LO_SPACE);
112 : static const int kNumberOfPreallocatedSpaces = CODE_SPACE + 1;
113 :
114 : // The number of spaces supported by the serializer. Spaces after LO_SPACE
115 : // (NEW_LO_SPACE and CODE_LO_SPACE) are not supported.
116 : static const int kNumberOfSpaces = LO_SPACE + 1;
117 :
118 : protected:
119 : static bool CanBeDeferred(HeapObject o);
120 :
121 : void RestoreExternalReferenceRedirectors(
122 : const std::vector<AccessorInfo>& accessor_infos);
123 : void RestoreExternalReferenceRedirectors(
124 : const std::vector<CallHandlerInfo>& call_handler_infos);
125 :
126 : #define UNUSED_SERIALIZER_BYTE_CODES(V) \
127 : V(0x0e) \
128 : V(0x2e) \
129 : V(0x3e) \
130 : V(0x3f) \
131 : V(0x4e) \
132 : V(0x58) \
133 : V(0x59) \
134 : V(0x5a) \
135 : V(0x5b) \
136 : V(0x5c) \
137 : V(0x5d) \
138 : V(0x5e) \
139 : V(0x5f) \
140 : V(0x67) \
141 : V(0x6e) \
142 : V(0x76) \
143 : V(0x79) \
144 : V(0x7a) \
145 : V(0x7b) \
146 : V(0x7c)
147 :
148 : // ---------- byte code range 0x00..0x7f ----------
149 : // Byte codes in this range represent Where, HowToCode and WhereToPoint.
150 : // Where the pointed-to object can be found:
151 : // The static assert below will trigger when the number of preallocated spaces
152 : // changed. If that happens, update the bytecode ranges in the comments below.
153 : STATIC_ASSERT(6 == kNumberOfSpaces);
154 : enum Where {
155 : // 0x00..0x05 Allocate new object, in specified space.
156 : kNewObject = 0x00,
157 : // 0x08..0x0d Reference to previous object from space.
158 : kBackref = 0x08,
159 : // 0x10..0x15 Reference to previous object from space after skip.
160 : kBackrefWithSkip = 0x10,
161 :
162 : // 0x06 Object in the partial snapshot cache.
163 : kPartialSnapshotCache = 0x06,
164 : // 0x07 External reference referenced by id.
165 : kExternalReference = 0x07,
166 :
167 : // 0x16 Root array item.
168 : kRootArray = 0x16,
169 : // 0x17 Object provided in the attached list.
170 : kAttachedReference = 0x17,
171 : // 0x18 Object in the read-only object cache.
172 : kReadOnlyObjectCache = 0x18,
173 :
174 : // 0x0f Misc, see below (incl. 0x2f, 0x4f, 0x6f).
175 : // 0x18..0x1f Misc, see below (incl. 0x38..0x3f, 0x58..0x5f, 0x78..0x7f).
176 : };
177 :
178 : static const int kWhereMask = 0x1f;
179 : static const int kSpaceMask = 7;
180 : STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
181 :
182 : // How to code the pointer to the object.
183 : enum HowToCode {
184 : // Straight pointer.
185 : kPlain = 0,
186 : // A pointer inlined in code. What this means depends on the architecture.
187 : kFromCode = 0x20
188 : };
189 :
190 : static const int kHowToCodeMask = 0x20;
191 :
192 : // Where to point within the object.
193 : enum WhereToPoint {
194 : // Points to start of object
195 : kStartOfObject = 0,
196 : // Points to instruction in code object or payload of cell.
197 : kInnerPointer = 0x40
198 : };
199 :
200 : static const int kWhereToPointMask = 0x40;
201 :
202 : // ---------- Misc ----------
203 : // Skip.
204 : static const int kSkip = 0x0f;
205 : // Do nothing, used for padding.
206 : static const int kNop = 0x2f;
207 : // Move to next reserved chunk.
208 : static const int kNextChunk = 0x4f;
209 : // Deferring object content.
210 : static const int kDeferred = 0x6f;
211 : // Alignment prefixes 0x19..0x1b
212 : static const int kAlignmentPrefix = 0x19;
213 : // A tag emitted at strategic points in the snapshot to delineate sections.
214 : // If the deserializer does not find these at the expected moments then it
215 : // is an indication that the snapshot and the VM do not fit together.
216 : // Examine the build process for architecture, version or configuration
217 : // mismatches.
218 : static const int kSynchronize = 0x1c;
219 : // Repeats of variable length.
220 : static const int kVariableRepeat = 0x1d;
221 : // Raw data of variable length.
222 :
223 : // Used for embedder-allocated backing stores for TypedArrays.
224 : static const int kOffHeapBackingStore = 0x1e;
225 :
226 : // Used for embedder-provided serialization data for embedder fields.
227 : static const int kEmbedderFieldsData = 0x1f;
228 :
229 : static const int kVariableRawCode = 0x39;
230 : static const int kVariableRawData = 0x3a;
231 :
232 : static const int kInternalReference = 0x3b;
233 : static const int kInternalReferenceEncoded = 0x3c;
234 :
235 : // Used to encode external references provided through the API.
236 : static const int kApiReference = 0x3d;
237 :
238 : // In-place weak references
239 : static const int kClearedWeakReference = 0x7d;
240 : static const int kWeakPrefix = 0x7e;
241 :
242 : // Encodes an off-heap instruction stream target.
243 : static const int kOffHeapTarget = 0x7f;
244 :
245 : // ---------- byte code range 0x80..0xff ----------
246 : // First 32 root array items.
247 : static const int kNumberOfRootArrayConstants = 0x20;
248 : // 0x80..0x9f
249 : static const int kRootArrayConstants = 0x80;
250 : // 0xa0..0xbf
251 : static const int kRootArrayConstantsWithSkip = 0xa0;
252 : static const int kRootArrayConstantsMask = 0x1f;
253 :
254 : // 32 common raw data lengths.
255 : static const int kNumberOfFixedRawData = 0x20;
256 : // 0xc0..0xdf
257 : static const int kFixedRawData = 0xc0;
258 : static const int kOnePointerRawData = kFixedRawData;
259 : static const int kFixedRawDataStart = kFixedRawData - 1;
260 :
261 : // 16 repeats lengths.
262 : static const int kNumberOfFixedRepeat = 0x10;
263 : // 0xe0..0xef
264 : static const int kFixedRepeat = 0xe0;
265 : static const int kFixedRepeatStart = kFixedRepeat - 1;
266 :
267 : // 8 hot (recently seen or back-referenced) objects with optional skip.
268 : static const int kNumberOfHotObjects = 8;
269 : STATIC_ASSERT(kNumberOfHotObjects == HotObjectsList::kSize);
270 : // 0xf0..0xf7
271 : static const int kHotObject = 0xf0;
272 : // 0xf8..0xff
273 : static const int kHotObjectWithSkip = 0xf8;
274 : static const int kHotObjectMask = 0x07;
275 :
276 : // ---------- special values ----------
277 : static const int kAnyOldSpace = -1;
278 :
279 : // Sentinel after a new object to indicate that double alignment is needed.
280 : static const int kDoubleAlignmentSentinel = 0;
281 :
282 : // ---------- member variable ----------
283 : HotObjectsList hot_objects_;
284 : };
285 :
286 : class SerializedData {
287 : public:
288 : class Reservation {
289 : public:
290 3421465 : Reservation() : reservation_(0) {}
291 : explicit Reservation(uint32_t size)
292 16022 : : reservation_(ChunkSizeBits::encode(size)) {}
293 :
294 3421296 : uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); }
295 3421092 : bool is_last() const { return IsLastChunkBits::decode(reservation_); }
296 :
297 6672 : void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); }
298 :
299 : private:
300 : uint32_t reservation_;
301 : };
302 :
303 : SerializedData(byte* data, int size)
304 217720 : : data_(data), size_(size), owns_data_(false) {}
305 1112 : SerializedData() : data_(nullptr), size_(0), owns_data_(false) {}
306 : SerializedData(SerializedData&& other) V8_NOEXCEPT
307 : : data_(other.data_),
308 : size_(other.size_),
309 214 : owns_data_(other.owns_data_) {
310 : // Ensure |other| will not attempt to destroy our data in destructor.
311 214 : other.owns_data_ = false;
312 : }
313 :
314 219049 : virtual ~SerializedData() {
315 219049 : if (owns_data_) DeleteArray<byte>(data_);
316 219049 : }
317 :
318 217895 : uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
319 :
320 : class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
321 : class IsLastChunkBits : public BitField<bool, 31, 1> {};
322 :
323 : static constexpr uint32_t kMagicNumberOffset = 0;
324 : static constexpr uint32_t kMagicNumber =
325 : 0xC0DE0000 ^ ExternalReferenceTable::kSize;
326 :
327 : protected:
328 : void SetHeaderValue(uint32_t offset, uint32_t value) {
329 4498 : 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 654866 : offset);
335 : }
336 :
337 : void AllocateData(uint32_t size);
338 :
339 1112 : void SetMagicNumber() { SetHeaderValue(kMagicNumberOffset, kMagicNumber); }
340 :
341 : byte* data_;
342 : uint32_t size_;
343 : bool owns_data_;
344 :
345 : private:
346 : DISALLOW_COPY_AND_ASSIGN(SerializedData);
347 : };
348 :
349 : class Checksum {
350 : public:
351 : explicit Checksum(Vector<const byte> payload) {
352 : #ifdef MEMORY_SANITIZER
353 : // Computing the checksum includes padding bytes for objects like strings.
354 : // Mark every object as initialized in the code serializer.
355 : MSAN_MEMORY_IS_INITIALIZED(payload.start(), payload.length());
356 : #endif // MEMORY_SANITIZER
357 : // Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
358 : uintptr_t a = 1;
359 : uintptr_t b = 0;
360 : const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
361 : DCHECK(IsAligned(payload.length(), kIntptrSize));
362 63566 : const uintptr_t* end = cur + payload.length() / kIntptrSize;
363 1946815646 : while (cur < end) {
364 : // Unsigned overflow expected and intended.
365 1946752080 : a += *cur++;
366 1946752080 : b += a;
367 : }
368 : #if V8_HOST_ARCH_64_BIT
369 63566 : a ^= a >> 32;
370 63566 : b ^= b >> 32;
371 : #endif // V8_HOST_ARCH_64_BIT
372 63566 : a_ = static_cast<uint32_t>(a);
373 63566 : b_ = static_cast<uint32_t>(b);
374 : }
375 :
376 63001 : bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
377 :
378 : uint32_t a() const { return a_; }
379 : uint32_t b() const { return b_; }
380 :
381 : private:
382 : uint32_t a_;
383 : uint32_t b_;
384 :
385 : DISALLOW_COPY_AND_ASSIGN(Checksum);
386 : };
387 :
388 : } // namespace internal
389 : } // namespace v8
390 :
391 : #endif // V8_SNAPSHOT_SERIALIZER_COMMON_H_
|