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 217734 : HotObjectsList() : index_(0) {}
64 :
65 : void Add(HeapObject object) {
66 : DCHECK(!AllowHeapAllocation::IsAllowed());
67 398681505 : circular_queue_[index_] = object;
68 398681505 : index_ = (index_ + 1) & kSizeMask;
69 : }
70 :
71 : HeapObject Get(int index) {
72 : DCHECK(!AllowHeapAllocation::IsAllowed());
73 : DCHECK(!circular_queue_[index].is_null());
74 512093619 : return circular_queue_[index];
75 : }
76 :
77 : static const int kNotFound = -1;
78 :
79 : int Find(HeapObject object) {
80 : DCHECK(!AllowHeapAllocation::IsAllowed());
81 131018928 : for (int i = 0; i < kSize; i++) {
82 63229345 : 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 653232 : 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 : // clang-format off
127 : #define UNUSED_SERIALIZER_BYTE_CODES(V) \
128 : V(0x06) V(0x07) V(0x0e) V(0x0f) \
129 : /* Free range 0x26..0x2f */ \
130 : V(0x26) V(0x27) \
131 : V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) \
132 : /* Free range 0x30..0x3f */ \
133 : V(0x30) V(0x31) V(0x32) V(0x33) V(0x34) V(0x35) V(0x36) V(0x37) \
134 : V(0x38) V(0x39) V(0x3a) V(0x3b) V(0x3c) V(0x3d) V(0x3e) V(0x3f) \
135 : /* Free range 0x97..0x9f */ \
136 : V(0x98) V(0x99) V(0x9a) V(0x9b) V(0x9c) V(0x9d) V(0x9e) V(0x9f) \
137 : /* Free range 0xa0..0xaf */ \
138 : V(0xa0) V(0xa1) V(0xa2) V(0xa3) V(0xa4) V(0xa5) V(0xa6) V(0xa7) \
139 : V(0xa8) V(0xa9) V(0xaa) V(0xab) V(0xac) V(0xad) V(0xae) V(0xaf) \
140 : /* Free range 0xb0..0xbf */ \
141 : V(0xb0) V(0xb1) V(0xb2) V(0xb3) V(0xb4) V(0xb5) V(0xb6) V(0xb7) \
142 : V(0xb8) V(0xb9) V(0xba) V(0xbb) V(0xbc) V(0xbd) V(0xbe) V(0xbf) \
143 : /* Free range 0xc0..0xcf */ \
144 : V(0xc0) V(0xc1) V(0xc2) V(0xc3) V(0xc4) V(0xc5) V(0xc6) V(0xc7) \
145 : V(0xc8) V(0xc9) V(0xca) V(0xcb) V(0xcc) V(0xcd) V(0xce) V(0xcf) \
146 : /* Free range 0xd0..0xdf */ \
147 : V(0xd0) V(0xd1) V(0xd2) V(0xd3) V(0xd4) V(0xd5) V(0xd6) V(0xd7) \
148 : V(0xd8) V(0xd9) V(0xda) V(0xdb) V(0xdc) V(0xdd) V(0xde) V(0xdf) \
149 : /* Free range 0xe0..0xef */ \
150 : V(0xe0) V(0xe1) V(0xe2) V(0xe3) V(0xe4) V(0xe5) V(0xe6) V(0xe7) \
151 : V(0xe8) V(0xe9) V(0xea) V(0xeb) V(0xec) V(0xed) V(0xee) V(0xef) \
152 : /* Free range 0xf0..0xff */ \
153 : V(0xf0) V(0xf1) V(0xf2) V(0xf3) V(0xf4) V(0xf5) V(0xf6) V(0xf7) \
154 : V(0xf8) V(0xf9) V(0xfa) V(0xfb) V(0xfc) V(0xfd) V(0xfe) V(0xff)
155 : // clang-format on
156 :
157 : // The static assert below will trigger when the number of preallocated spaces
158 : // changed. If that happens, update the kNewObject and kBackref bytecode
159 : // ranges in the comments below.
160 : STATIC_ASSERT(6 == kNumberOfSpaces);
161 : static const int kSpaceMask = 7;
162 : STATIC_ASSERT(kNumberOfSpaces <= kSpaceMask + 1);
163 :
164 : // First 32 root array items.
165 : static const int kNumberOfRootArrayConstants = 0x20;
166 : static const int kRootArrayConstantsMask = 0x1f;
167 :
168 : // 32 common raw data lengths.
169 : static const int kNumberOfFixedRawData = 0x20;
170 :
171 : // 16 repeats lengths.
172 : static const int kNumberOfFixedRepeat = 0x10;
173 :
174 : // 8 hot (recently seen or back-referenced) objects with optional skip.
175 : static const int kNumberOfHotObjects = 8;
176 : STATIC_ASSERT(kNumberOfHotObjects == HotObjectsList::kSize);
177 : static const int kHotObjectMask = 0x07;
178 :
179 : enum Bytecode {
180 : //
181 : // ---------- byte code range 0x00..0x0f ----------
182 : //
183 :
184 : // 0x00..0x05 Allocate new object, in specified space.
185 : kNewObject = 0x00,
186 : // 0x08..0x0d Reference to previous object from specified space.
187 : kBackref = 0x08,
188 :
189 : //
190 : // ---------- byte code range 0x10..0x25 ----------
191 : //
192 :
193 : // Object in the partial snapshot cache.
194 : kPartialSnapshotCache = 0x10,
195 : // Root array item.
196 : kRootArray,
197 : // Object provided in the attached list.
198 : kAttachedReference,
199 : // Object in the read-only object cache.
200 : kReadOnlyObjectCache,
201 : // Do nothing, used for padding.
202 : kNop,
203 : // Move to next reserved chunk.
204 : kNextChunk,
205 : // Deferring object content.
206 : kDeferred,
207 : // 3 alignment prefixes 0x17..0x19
208 : kAlignmentPrefix = 0x17,
209 : // A tag emitted at strategic points in the snapshot to delineate sections.
210 : // If the deserializer does not find these at the expected moments then it
211 : // is an indication that the snapshot and the VM do not fit together.
212 : // Examine the build process for architecture, version or configuration
213 : // mismatches.
214 : kSynchronize = 0x1a,
215 : // Repeats of variable length.
216 : kVariableRepeat,
217 : // Used for embedder-allocated backing stores for TypedArrays.
218 : kOffHeapBackingStore,
219 : // Used for embedder-provided serialization data for embedder fields.
220 : kEmbedderFieldsData,
221 : // Raw data of variable length.
222 : kVariableRawCode,
223 : kVariableRawData,
224 : // Used to encode external references provided through the API.
225 : kApiReference,
226 : // External reference referenced by id.
227 : kExternalReference,
228 : // Internal reference of a code objects in code stream.
229 : kInternalReference,
230 : // In-place weak references.
231 : kClearedWeakReference,
232 : kWeakPrefix,
233 : // Encodes an off-heap instruction stream target.
234 : kOffHeapTarget,
235 :
236 : //
237 : // ---------- byte code range 0x40..0x7f ----------
238 : //
239 :
240 : // 0x40..0x5f
241 : kRootArrayConstants = 0x40,
242 :
243 : // 0x60..0x7f
244 : kFixedRawData = 0x60,
245 : kOnePointerRawData = kFixedRawData,
246 : kFixedRawDataStart = kFixedRawData - 1,
247 :
248 : //
249 : // ---------- byte code range 0x80..0x9f ----------
250 : //
251 :
252 : // 0x80..0x8f
253 : kFixedRepeat = 0x80,
254 :
255 : // 0x90..0x97
256 : kHotObject = 0x90,
257 : };
258 :
259 : //
260 : // Some other constants.
261 : //
262 : static const int kAnyOldSpace = -1;
263 :
264 : // Sentinel after a new object to indicate that double alignment is needed.
265 : static const int kDoubleAlignmentSentinel = 0;
266 :
267 : // Repeat count encoding helpers.
268 : static const int kFirstEncodableRepeatCount = 2;
269 : static const int kLastEncodableFixedRepeatCount =
270 : kFirstEncodableRepeatCount + kNumberOfFixedRepeat - 1;
271 : static const int kFirstEncodableVariableRepeatCount =
272 : kLastEncodableFixedRepeatCount + 1;
273 :
274 : // Encodes repeat count into a fixed repeat bytecode.
275 : static int EncodeFixedRepeat(int repeat_count) {
276 : DCHECK(IsInRange(repeat_count, kFirstEncodableRepeatCount,
277 : kLastEncodableFixedRepeatCount));
278 475652 : return kFixedRepeat + repeat_count - kFirstEncodableRepeatCount;
279 : }
280 :
281 : // Decodes repeat count from a fixed repeat bytecode.
282 : static int DecodeFixedRepeatCount(int bytecode) {
283 : DCHECK(IsInRange(bytecode, kFixedRepeat + 0,
284 : kFixedRepeat + kNumberOfFixedRepeat));
285 86993233 : return bytecode - kFixedRepeat + kFirstEncodableRepeatCount;
286 : }
287 :
288 : // Encodes repeat count into a serialized variable repeat count value.
289 : static int EncodeVariableRepeatCount(int repeat_count) {
290 : DCHECK_LE(kFirstEncodableVariableRepeatCount, repeat_count);
291 1869 : return repeat_count - kFirstEncodableVariableRepeatCount;
292 : }
293 :
294 : // Decodes repeat count from a serialized variable repeat count value.
295 : static int DecodeVariableRepeatCount(int value) {
296 : DCHECK_LE(0, value);
297 524559 : return value + kFirstEncodableVariableRepeatCount;
298 : }
299 :
300 : // ---------- member variable ----------
301 : HotObjectsList hot_objects_;
302 : };
303 :
304 : class SerializedData {
305 : public:
306 : class Reservation {
307 : public:
308 3595471 : Reservation() : reservation_(0) {}
309 : explicit Reservation(uint32_t size)
310 16931 : : reservation_(ChunkSizeBits::encode(size)) {}
311 :
312 3595269 : uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); }
313 3595055 : bool is_last() const { return IsLastChunkBits::decode(reservation_); }
314 :
315 6822 : void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); }
316 :
317 : private:
318 : uint32_t reservation_;
319 : };
320 :
321 : SerializedData(byte* data, int size)
322 216648 : : data_(data), size_(size), owns_data_(false) {}
323 1137 : SerializedData() : data_(nullptr), size_(0), owns_data_(false) {}
324 : SerializedData(SerializedData&& other) V8_NOEXCEPT
325 209 : : data_(other.data_),
326 209 : size_(other.size_),
327 627 : owns_data_(other.owns_data_) {
328 : // Ensure |other| will not attempt to destroy our data in destructor.
329 209 : other.owns_data_ = false;
330 : }
331 :
332 436036 : virtual ~SerializedData() {
333 218018 : if (owns_data_) DeleteArray<byte>(data_);
334 0 : }
335 :
336 : uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
337 :
338 : class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
339 : class IsLastChunkBits : public BitField<bool, 31, 1> {};
340 :
341 : static constexpr uint32_t kMagicNumberOffset = 0;
342 : static constexpr uint32_t kMagicNumber =
343 : 0xC0DE0000 ^ ExternalReferenceTable::kSize;
344 :
345 : protected:
346 : void SetHeaderValue(uint32_t offset, uint32_t value) {
347 4144 : WriteLittleEndianValue(reinterpret_cast<Address>(data_) + offset, value);
348 : }
349 :
350 : uint32_t GetHeaderValue(uint32_t offset) const {
351 651411 : return ReadLittleEndianValue<uint32_t>(reinterpret_cast<Address>(data_) +
352 : offset);
353 : }
354 :
355 : void AllocateData(uint32_t size);
356 :
357 : void SetMagicNumber() { SetHeaderValue(kMagicNumberOffset, kMagicNumber); }
358 :
359 : byte* data_;
360 : uint32_t size_;
361 : bool owns_data_;
362 :
363 : private:
364 : DISALLOW_COPY_AND_ASSIGN(SerializedData);
365 : };
366 :
367 : class Checksum {
368 : public:
369 : explicit Checksum(Vector<const byte> payload) {
370 : #ifdef MEMORY_SANITIZER
371 : // Computing the checksum includes padding bytes for objects like strings.
372 : // Mark every object as initialized in the code serializer.
373 : MSAN_MEMORY_IS_INITIALIZED(payload.start(), payload.length());
374 : #endif // MEMORY_SANITIZER
375 : // Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
376 : uintptr_t a = 1;
377 : uintptr_t b = 0;
378 : const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
379 : DCHECK(IsAligned(payload.length(), kIntptrSize));
380 63106 : const uintptr_t* end = cur + payload.length() / kIntptrSize;
381 1971490351 : while (cur < end) {
382 : // Unsigned overflow expected and intended.
383 1971427245 : a += *cur++;
384 1971427245 : b += a;
385 : }
386 : #if V8_HOST_ARCH_64_BIT
387 63106 : a ^= a >> 32;
388 63106 : b ^= b >> 32;
389 : #endif // V8_HOST_ARCH_64_BIT
390 63106 : a_ = static_cast<uint32_t>(a);
391 63106 : b_ = static_cast<uint32_t>(b);
392 : }
393 :
394 62535 : bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
395 :
396 : uint32_t a() const { return a_; }
397 : uint32_t b() const { return b_; }
398 :
399 : private:
400 : uint32_t a_;
401 : uint32_t b_;
402 :
403 : DISALLOW_COPY_AND_ASSIGN(Checksum);
404 : };
405 :
406 : } // namespace internal
407 : } // namespace v8
408 :
409 : #endif // V8_SNAPSHOT_SERIALIZER_COMMON_H_
|