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 | 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 | HotObjectsList() : index_(0) {} |
64 | |
65 | void Add(HeapObject object) { |
66 | DCHECK(!AllowHeapAllocation::IsAllowed()); |
67 | circular_queue_[index_] = object; |
68 | index_ = (index_ + 1) & kSizeMask; |
69 | } |
70 | |
71 | HeapObject Get(int index) { |
72 | DCHECK(!AllowHeapAllocation::IsAllowed()); |
73 | DCHECK(!circular_queue_[index].is_null()); |
74 | return circular_queue_[index]; |
75 | } |
76 | |
77 | static const int kNotFound = -1; |
78 | |
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 | |
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 | 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 | 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 | 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 | 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 | Reservation() : reservation_(0) {} |
309 | explicit Reservation(uint32_t size) |
310 | : reservation_(ChunkSizeBits::encode(size)) {} |
311 | |
312 | uint32_t chunk_size() const { return ChunkSizeBits::decode(reservation_); } |
313 | bool is_last() const { return IsLastChunkBits::decode(reservation_); } |
314 | |
315 | void mark_as_last() { reservation_ |= IsLastChunkBits::encode(true); } |
316 | |
317 | private: |
318 | uint32_t reservation_; |
319 | }; |
320 | |
321 | SerializedData(byte* data, int size) |
322 | : data_(data), size_(size), owns_data_(false) {} |
323 | SerializedData() : data_(nullptr), size_(0), owns_data_(false) {} |
324 | SerializedData(SerializedData&& other) V8_NOEXCEPT |
325 | : data_(other.data_), |
326 | size_(other.size_), |
327 | owns_data_(other.owns_data_) { |
328 | // Ensure |other| will not attempt to destroy our data in destructor. |
329 | other.owns_data_ = false; |
330 | } |
331 | |
332 | virtual ~SerializedData() { |
333 | if (owns_data_) DeleteArray<byte>(data_); |
334 | } |
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 (uint32_t offset, uint32_t value) { |
347 | WriteLittleEndianValue(reinterpret_cast<Address>(data_) + offset, value); |
348 | } |
349 | |
350 | uint32_t (uint32_t offset) const { |
351 | 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 | const uintptr_t* end = cur + payload.length() / kIntptrSize; |
381 | while (cur < end) { |
382 | // Unsigned overflow expected and intended. |
383 | a += *cur++; |
384 | b += a; |
385 | } |
386 | #if V8_HOST_ARCH_64_BIT |
387 | a ^= a >> 32; |
388 | b ^= b >> 32; |
389 | #endif // V8_HOST_ARCH_64_BIT |
390 | a_ = static_cast<uint32_t>(a); |
391 | b_ = static_cast<uint32_t>(b); |
392 | } |
393 | |
394 | 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_ |
410 | |