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
12namespace v8 {
13namespace internal {
14
15class 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
152class 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