1 | // Copyright 2018 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_REFERENCES_H_ |
6 | #define V8_SNAPSHOT_REFERENCES_H_ |
7 | |
8 | #include "src/assert-scope.h" |
9 | #include "src/base/hashmap.h" |
10 | #include "src/utils.h" |
11 | |
12 | namespace v8 { |
13 | namespace internal { |
14 | |
15 | class SerializerReference { |
16 | private: |
17 | enum SpecialValueType { |
18 | kInvalidValue, |
19 | kAttachedReference, |
20 | kOffHeapBackingStore, |
21 | kBuiltinReference, |
22 | }; |
23 | |
24 | static const int kSpecialValueSpace = LAST_SPACE + 1; |
25 | STATIC_ASSERT(kSpecialValueSpace < (1 << kSpaceTagSize)); |
26 | |
27 | SerializerReference(SpecialValueType type, uint32_t value) |
28 | : bitfield_(SpaceBits::encode(kSpecialValueSpace) | |
29 | SpecialValueTypeBits::encode(type)), |
30 | value_(value) {} |
31 | |
32 | public: |
33 | SerializerReference() : SerializerReference(kInvalidValue, 0) {} |
34 | |
35 | SerializerReference(uint32_t space, uint32_t chunk_index, |
36 | uint32_t chunk_offset) |
37 | : bitfield_(SpaceBits::encode(space) | |
38 | ChunkIndexBits::encode(chunk_index)), |
39 | value_(chunk_offset) {} |
40 | |
41 | static SerializerReference BackReference(AllocationSpace space, |
42 | uint32_t chunk_index, |
43 | uint32_t chunk_offset) { |
44 | DCHECK(IsAligned(chunk_offset, kObjectAlignment)); |
45 | DCHECK_LT(space, LO_SPACE); |
46 | return SerializerReference(space, chunk_index, chunk_offset); |
47 | } |
48 | |
49 | static SerializerReference MapReference(uint32_t index) { |
50 | return SerializerReference(MAP_SPACE, 0, index); |
51 | } |
52 | |
53 | static SerializerReference OffHeapBackingStoreReference(uint32_t index) { |
54 | return SerializerReference(kOffHeapBackingStore, index); |
55 | } |
56 | |
57 | static SerializerReference LargeObjectReference(uint32_t index) { |
58 | return SerializerReference(LO_SPACE, 0, index); |
59 | } |
60 | |
61 | static SerializerReference AttachedReference(uint32_t index) { |
62 | return SerializerReference(kAttachedReference, index); |
63 | } |
64 | |
65 | static SerializerReference BuiltinReference(uint32_t index) { |
66 | return SerializerReference(kBuiltinReference, index); |
67 | } |
68 | |
69 | bool is_valid() const { |
70 | return SpaceBits::decode(bitfield_) != kSpecialValueSpace || |
71 | SpecialValueTypeBits::decode(bitfield_) != kInvalidValue; |
72 | } |
73 | |
74 | bool is_back_reference() const { |
75 | return SpaceBits::decode(bitfield_) <= LAST_SPACE; |
76 | } |
77 | |
78 | AllocationSpace space() const { |
79 | DCHECK(is_back_reference()); |
80 | return static_cast<AllocationSpace>(SpaceBits::decode(bitfield_)); |
81 | } |
82 | |
83 | uint32_t chunk_offset() const { |
84 | DCHECK(is_back_reference()); |
85 | return value_; |
86 | } |
87 | |
88 | uint32_t chunk_index() const { |
89 | DCHECK(space() != MAP_SPACE && space() != LO_SPACE); |
90 | return ChunkIndexBits::decode(bitfield_); |
91 | } |
92 | |
93 | uint32_t map_index() const { |
94 | DCHECK_EQ(MAP_SPACE, SpaceBits::decode(bitfield_)); |
95 | return value_; |
96 | } |
97 | |
98 | bool is_off_heap_backing_store_reference() const { |
99 | return SpaceBits::decode(bitfield_) == kSpecialValueSpace && |
100 | SpecialValueTypeBits::decode(bitfield_) == kOffHeapBackingStore; |
101 | } |
102 | |
103 | uint32_t off_heap_backing_store_index() const { |
104 | DCHECK(is_off_heap_backing_store_reference()); |
105 | return value_; |
106 | } |
107 | |
108 | uint32_t large_object_index() const { |
109 | DCHECK_EQ(LO_SPACE, SpaceBits::decode(bitfield_)); |
110 | return value_; |
111 | } |
112 | |
113 | bool is_attached_reference() const { |
114 | return SpaceBits::decode(bitfield_) == kSpecialValueSpace && |
115 | SpecialValueTypeBits::decode(bitfield_) == kAttachedReference; |
116 | } |
117 | |
118 | uint32_t attached_reference_index() const { |
119 | DCHECK(is_attached_reference()); |
120 | return value_; |
121 | } |
122 | |
123 | bool is_builtin_reference() const { |
124 | return SpaceBits::decode(bitfield_) == kSpecialValueSpace && |
125 | SpecialValueTypeBits::decode(bitfield_) == kBuiltinReference; |
126 | } |
127 | |
128 | uint32_t builtin_index() const { |
129 | DCHECK(is_builtin_reference()); |
130 | return value_; |
131 | } |
132 | |
133 | private: |
134 | class SpaceBits : public BitField<int, 0, kSpaceTagSize> {}; |
135 | class ChunkIndexBits |
136 | : public BitField<uint32_t, SpaceBits::kNext, 32 - kSpaceTagSize> {}; |
137 | class SpecialValueTypeBits |
138 | : public BitField<SpecialValueType, SpaceBits::kNext, |
139 | 32 - kSpaceTagSize> {}; |
140 | |
141 | // We use two fields to store a reference. |
142 | // In case of a normal back reference, the bitfield_ stores the space and |
143 | // the chunk index. In case of special references, it uses a special value |
144 | // for space and stores the special value type. |
145 | uint32_t bitfield_; |
146 | // value_ stores either chunk offset or special value. |
147 | uint32_t value_; |
148 | |
149 | friend class SerializerReferenceMap; |
150 | }; |
151 | |
152 | class SerializerReferenceMap |
153 | : public base::TemplateHashMapImpl<uintptr_t, SerializerReference, |
154 | base::KeyEqualityMatcher<intptr_t>, |
155 | base::DefaultAllocationPolicy> { |
156 | public: |
157 | using Entry = base::TemplateHashMapEntry<uintptr_t, SerializerReference>; |
158 | |
159 | SerializerReferenceMap() : attached_reference_index_(0) {} |
160 | |
161 | SerializerReference LookupReference(void* value) const { |
162 | uintptr_t key = Key(value); |
163 | Entry* entry = Lookup(key, Hash(key)); |
164 | if (entry == nullptr) return SerializerReference(); |
165 | return entry->value; |
166 | } |
167 | |
168 | void Add(void* obj, SerializerReference reference) { |
169 | DCHECK(reference.is_valid()); |
170 | DCHECK(!LookupReference(obj).is_valid()); |
171 | uintptr_t key = Key(obj); |
172 | LookupOrInsert(key, Hash(key))->value = reference; |
173 | } |
174 | |
175 | SerializerReference AddAttachedReference(void* attached_reference) { |
176 | SerializerReference reference = |
177 | SerializerReference::AttachedReference(attached_reference_index_++); |
178 | Add(attached_reference, reference); |
179 | return reference; |
180 | } |
181 | |
182 | private: |
183 | static inline uintptr_t Key(void* value) { |
184 | return reinterpret_cast<uintptr_t>(value); |
185 | } |
186 | |
187 | static uint32_t Hash(uintptr_t key) { return static_cast<uint32_t>(key); } |
188 | |
189 | DISALLOW_HEAP_ALLOCATION(no_allocation_) |
190 | int attached_reference_index_; |
191 | DISALLOW_COPY_AND_ASSIGN(SerializerReferenceMap); |
192 | }; |
193 | |
194 | } // namespace internal |
195 | } // namespace v8 |
196 | |
197 | #endif // V8_SNAPSHOT_REFERENCES_H_ |
198 | |