v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-forwarding-table-inl.h
Go to the documentation of this file.
1// Copyright 2022 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_OBJECTS_STRING_FORWARDING_TABLE_INL_H_
6#define V8_OBJECTS_STRING_FORWARDING_TABLE_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
11#include "src/base/atomicops.h"
12#include "src/common/globals.h"
13#include "src/heap/safepoint.h"
16#include "src/objects/slots.h"
18// Has to be the last include (doesn't have include guards):
20
21namespace v8 {
22namespace internal {
23
25 public:
29
33
34 inline uint32_t raw_hash(PtrComprCageBase cage_base) const;
36 bool* is_one_byte) const;
37
41
45
49
53
57
58 inline void set_raw_hash_if_empty(uint32_t raw_hash);
59 inline void set_external_resource(
60 v8::String::ExternalStringResourceBase* resource, bool is_one_byte);
64
65 inline void SetInternalized(Tagged<String> string, Tagged<String> forward_to);
66 inline void SetExternal(Tagged<String> string,
68 bool is_one_byte, uint32_t raw_hash);
69 inline bool TryUpdateExternalResource(
70 v8::String::ExternalStringResourceBase* resource, bool is_one_byte);
71 inline bool TryUpdateExternalResource(Address address);
72 inline void DisposeExternalResource();
73 // Dispose the external resource if the original string has transitioned
74 // to an external string and the resource used for the transition is different
75 // than the one in the record.
76 inline void DisposeUnusedExternalResource(Isolate* isolate,
78
79 private:
83
87
88 static constexpr intptr_t kExternalResourceIsOneByteTag = 1;
89 static constexpr intptr_t kExternalResourceEncodingMask = 1;
90 static constexpr intptr_t kExternalResourceAddressMask =
91 ~kExternalResourceEncodingMask;
92
93 // Always a pointer to the string that needs to be transitioned.
95 // The field either stores the forward string object, or a raw hash.
96 // For strings forwarded to an internalized string (to be converted to a
97 // ThinString during GC), this field always contrains the internalized string
98 // object.
99 // It is guaranteed that only computed hash values (LSB = 0) are stored,
100 // therefore a raw hash is distinguishable from a string object by the
101 // heap object tag.
102 // Raw hashes can be overwritten by forward string objects, whereas
103 // forward string objects will never be overwritten once set.
105 // Although this is an external pointer, we are using Address instead of
106 // ExternalPointer_t to not have to deal with the ExternalPointerTable.
107 // This is OK, as the StringForwardingTable is outside of the V8 sandbox.
108 // The LSB is used to indicate whether the external resource is a one-byte
109 // (LSB = 1) or two-byte (LSB = 0) external string resource.
111
112 // Possible string transitions and how they affect the fields of the record:
113 // Shared string (not in the table) --> Interalized
114 // forward_string_or_hash_ is set to the internalized string object.
115 // external_resource_ is nullptr.
116 // Shared string (not in the table) --> External
117 // forward_string_or_hash_ is set to the computed hash value of the string.
118 // external_resource_ is set to the address of the external resource.
119 // Shared string (in the table to be internalized) --> External
120 // forward_string_or_hash_ will not be overwritten. It will still contain
121 // the internalized string object from the previous transition.
122 // external_resource_ is set to the address of the external resource.
123 // Shared string (in the table to be made external) --> Internalized
124 // forward_string_or_hash_ (previously contained the computed hash value) is
125 // overwritten with the internalized string object.
126 // external_resource_ is not overwritten (still the external resource).
127
129};
130
132 PtrComprCageBase cage_base) const {
133 Tagged<Object> hash_or_string = ForwardStringObjectOrHash(cage_base);
134 uint32_t raw_hash;
135 if (IsHeapObject(hash_or_string)) {
136 raw_hash = Cast<String>(hash_or_string)->RawHash();
137 } else {
138 raw_hash = static_cast<uint32_t>(hash_or_string.ptr());
139 }
141 return raw_hash;
142}
143
146 Address address = ExternalResourceAddress();
147 *is_one_byte = (address & kExternalResourceEncodingMask) ==
148 kExternalResourceIsOneByteTag;
149 address &= kExternalResourceAddressMask;
150 return reinterpret_cast<v8::String::ExternalStringResourceBase*>(address);
151}
152
154 // Assert that computed hash values don't overlap with heap object tag.
155 static_assert((kHeapObjectTag & Name::kHashNotComputedMask) != 0);
158 AsAtomicTagged::Release_CompareAndSwap(&forward_string_or_hash_,
159 unused_element().value(), raw_hash);
160}
161
163 v8::String::ExternalStringResourceBase* resource, bool is_one_byte) {
164 DCHECK_NOT_NULL(resource);
165 Address address = reinterpret_cast<Address>(resource);
166 if (is_one_byte && address != kNullAddress) {
167 address |= kExternalResourceIsOneByteTag;
168 }
169 set_external_resource(address);
170}
171
173 Tagged<String> forward_to) {
174 set_original_string(string);
175 set_forward_string(forward_to);
176 set_external_resource(kNullExternalPointer);
177}
178
181 bool is_one_byte, uint32_t raw_hash) {
182 set_original_string(string);
183 set_raw_hash_if_empty(raw_hash);
184 set_external_resource(resource, is_one_byte);
185}
186
188 v8::String::ExternalStringResourceBase* resource, bool is_one_byte) {
189 DCHECK_NOT_NULL(resource);
190 Address address = reinterpret_cast<Address>(resource);
191 if (is_one_byte && address != kNullAddress) {
192 address |= kExternalResourceIsOneByteTag;
193 }
194 return TryUpdateExternalResource(address);
195}
196
198 static_assert(kNullAddress == kNullExternalPointer);
199 // Don't set the external resource if another one is already stored. If we
200 // would simply overwrite the resource, the previously stored one would be
201 // leaked.
203 &external_resource_, kNullAddress, address) == kNullAddress;
204}
205
207 bool is_one_byte;
208 auto resource = external_resource(&is_one_byte);
209 DCHECK_NOT_NULL(resource);
210 resource->Dispose();
211}
212
214 Isolate* isolate, Tagged<String> original) {
215#ifdef DEBUG
216 Tagged<String> stored_original = original_string(isolate);
217 if (IsThinString(stored_original)) {
218 stored_original = Cast<ThinString>(stored_original)->actual();
219 }
220 DCHECK_EQ(original, stored_original);
221#endif
222 if (!IsExternalString(original)) return;
223 Address original_resource =
224 Cast<ExternalString>(original)->resource_as_address();
225 bool is_one_byte;
226 auto resource = external_resource(&is_one_byte);
227 if (resource != nullptr &&
228 reinterpret_cast<Address>(resource) != original_resource) {
229 resource->Dispose();
230 }
231}
232
234 public:
235 static std::unique_ptr<Block> New(int capacity);
236 explicit Block(int capacity);
237 int capacity() const { return capacity_; }
238 void* operator new(size_t size, int capacity);
239 void* operator new(size_t size) = delete;
240 void operator delete(void* data);
241
242 Record* record(int index) {
243 DCHECK_LT(index, capacity());
244 return &elements_[index];
245 }
246
247 const Record* record(int index) const {
248 DCHECK_LT(index, capacity());
249 return &elements_[index];
250 }
251
252 void UpdateAfterYoungEvacuation(PtrComprCageBase cage_base);
253 void UpdateAfterYoungEvacuation(PtrComprCageBase cage_base, int up_to_index);
254 void UpdateAfterFullEvacuation(PtrComprCageBase cage_base);
255 void UpdateAfterFullEvacuation(PtrComprCageBase cage_base, int up_to_index);
256
257 private:
258 const int capacity_;
260};
261
263 public:
265 using Allocator = std::allocator<Block*>;
266
267 explicit BlockVector(size_t capacity);
268 ~BlockVector();
269 size_t capacity() const { return capacity_; }
270
272 DCHECK_LT(index, size());
273 return base::AsAtomicPointer::Acquire_Load(&begin_[index]);
274 }
275
276 Block* LoadBlock(size_t index) {
277 DCHECK_LT(index, size());
278 return begin_[index];
279 }
280
281 void AddBlock(std::unique_ptr<Block> block) {
282 DCHECK_LT(size(), capacity());
283 base::AsAtomicPointer::Release_Store(&begin_[size_], block.release());
284 size_++;
285 }
286
287 static std::unique_ptr<BlockVector> Grow(BlockVector* data, size_t capacity,
288 const base::Mutex& mutex);
289
290 size_t size() const { return size_; }
291
292 private:
294 const size_t capacity_;
295 std::atomic<size_t> size_;
297};
298
300bool StringForwardingTable::empty() const { return size() == 0; }
301
302// static
304 uint32_t* index_in_block) {
305 DCHECK_GE(index, 0);
306 DCHECK_NOT_NULL(index_in_block);
307 // The block is the leftmost set bit of the index, corrected by the size
308 // of the first block.
309 const uint32_t block_index =
312 static_cast<uint32_t>(index + kInitialBlockSize)) -
314 *index_in_block = IndexInBlock(index, block_index);
315 return block_index;
316}
317
318// static
319uint32_t StringForwardingTable::IndexInBlock(int index, uint32_t block_index) {
320 DCHECK_GE(index, 0);
321 // Clear out the leftmost set bit (the block index) to get the index within
322 // the block.
323 return static_cast<uint32_t>(index + kInitialBlockSize) &
324 ~(1u << (block_index + kInitialBlockSizeHighestBit));
325}
326
327// static
328uint32_t StringForwardingTable::CapacityForBlock(uint32_t block_index) {
329 return 1u << (block_index + kInitialBlockSizeHighestBit);
330}
331
332template <typename Func>
334 if (empty()) return;
335 BlockVector* blocks = blocks_.load(std::memory_order_relaxed);
336 const uint32_t last_block_index = static_cast<uint32_t>(blocks->size() - 1);
337 for (uint32_t block_index = 0; block_index < last_block_index;
338 ++block_index) {
339 Block* block = blocks->LoadBlock(block_index);
340 for (int index = 0; index < block->capacity(); ++index) {
341 Record* rec = block->record(index);
342 callback(rec);
343 }
344 }
345 // Handle last block separately, as it is not filled to capacity.
346 const uint32_t max_index = IndexInBlock(size() - 1, last_block_index) + 1;
347 Block* block = blocks->LoadBlock(last_block_index);
348 for (uint32_t index = 0; index < max_index; ++index) {
349 Record* rec = block->record(index);
350 callback(rec);
351 }
352}
353
354} // namespace internal
355} // namespace v8
356
358
359#endif // V8_OBJECTS_STRING_FORWARDING_TABLE_INL_H_
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static void Release_Store(T *addr, typename std::remove_reference< T >::type new_value)
static T AcquireRelease_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
static T Acquire_Load(T *addr)
static T Release_CompareAndSwap(T *addr, typename std::remove_reference< T >::type old_value, typename std::remove_reference< T >::type new_value)
Tagged< Object > Acquire_Load() const
Definition slots-inl.h:74
void Release_Store(Tagged< Object > value) const
Definition slots-inl.h:104
static constexpr int kHashNotComputedMask
Definition name.h:131
static bool IsHashFieldComputed(uint32_t raw_hash_field)
Definition name-inl.h:96
void SetInternalized(Tagged< String > string, Tagged< String > forward_to)
bool TryUpdateExternalResource(v8::String::ExternalStringResourceBase *resource, bool is_one_byte)
uint32_t raw_hash(PtrComprCageBase cage_base) const
void set_external_resource(v8::String::ExternalStringResourceBase *resource, bool is_one_byte)
Tagged< String > forward_string(PtrComprCageBase cage_base) const
void SetExternal(Tagged< String > string, v8::String::ExternalStringResourceBase *, bool is_one_byte, uint32_t raw_hash)
Tagged< Object > ForwardStringObjectOrHash(PtrComprCageBase cage_base) const
Tagged< Object > OriginalStringObject(PtrComprCageBase cage_base) const
v8::String::ExternalStringResourceBase * external_resource(bool *is_one_byte) const
void DisposeUnusedExternalResource(Isolate *isolate, Tagged< String > original_string)
Tagged< String > original_string(PtrComprCageBase cage_base) const
static uint32_t IndexInBlock(int index, uint32_t block)
bool TryUpdateExternalResource(int index, T *resource)
static constexpr Tagged< Smi > unused_element()
static uint32_t CapacityForBlock(uint32_t block)
static uint32_t BlockForIndex(int index, uint32_t *index_in_block_out)
V8_INLINE void IterateElements(Func &&callback)
V8_INLINE constexpr StorageType ptr() const
const int size_
Definition assembler.cc:132
OptionalOpIndex index
Handle< FixedArray > elements_
Definition isolate.cc:1119
TNode< Object > callback
base::Mutex mutex
constexpr unsigned CountLeadingZeros(T value)
Definition bits.h:100
const intptr_t kHeapObjectTagMask
Definition v8-internal.h:75
constexpr ExternalPointer_t kNullExternalPointer
Address Tagged_t
Definition globals.h:547
constexpr int kBitsPerInt
Definition globals.h:687
const int kHeapObjectTag
Definition v8-internal.h:72
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:669
SlotTraits::TOffHeapObjectSlot OffHeapObjectSlot
Definition globals.h:1258
return value
Definition map-inl.h:893
static constexpr Address kNullAddress
Definition v8-internal.h:53
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_NO_UNIQUE_ADDRESS
Definition v8config.h:722