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
17namespace v8 {
18namespace internal {
19
20class CallHandlerInfo;
21class Isolate;
22
23class 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
61class 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.
101class 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
304class 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 SetHeaderValue(uint32_t offset, uint32_t value) {
347 WriteLittleEndianValue(reinterpret_cast<Address>(data_) + offset, value);
348 }
349
350 uint32_t GetHeaderValue(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
367class 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