[static-roots] Clear string padding faster

Clearing the exact amount of padding bytes apparently measurably
regresses some string operations. For freshly allocated strings we can
write into the payload area too, since that one is being written later.
This allows us to clear a statically known amount of padding bytes which
greatly speeds up the initialization.

Bug: chromium:1402898
Bug: v8:13466
Change-Id: Ib5fd4877a88c88fbf5247ed0e2c4b2de1775623d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4118772
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Jakob Linke <jgruber@chromium.org>
Commit-Queue: Olivier Flückiger <olivf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84980}
This commit is contained in:
Olivier Flückiger 2022-12-21 16:46:45 +00:00 committed by V8 LUCI CQ
parent dc950c32bd
commit bbe24f16c6
4 changed files with 27 additions and 31 deletions

View File

@ -674,10 +674,10 @@ MaybeHandle<SeqStringT> FactoryBase<Impl>::NewRawStringWithMap(
SeqStringT string =
SeqStringT::cast(AllocateRawWithImmortalMap(size, allocation, map));
DisallowGarbageCollection no_gc;
string.clear_padding_destructively(length);
string.set_length(length);
string.set_raw_hash_field(String::kEmptyHashField);
DCHECK_EQ(size, string.Size());
string.clear_padding();
return handle(string, isolate());
}
@ -1055,10 +1055,10 @@ FactoryBase<Impl>::AllocateRawOneByteInternalizedString(
map);
SeqOneByteString answer = SeqOneByteString::cast(result);
DisallowGarbageCollection no_gc;
answer.clear_padding_destructively(length);
answer.set_length(length);
answer.set_raw_hash_field(raw_hash_field);
DCHECK_EQ(size, answer.Size());
answer.clear_padding();
return handle(answer, isolate());
}
@ -1077,10 +1077,10 @@ FactoryBase<Impl>::AllocateRawTwoByteInternalizedString(
map),
map));
DisallowGarbageCollection no_gc;
answer.clear_padding_destructively(length);
answer.set_length(length);
answer.set_raw_hash_field(raw_hash_field);
DCHECK_EQ(size, answer.Size());
answer.clear_padding();
return handle(answer, isolate());
}

View File

@ -1476,24 +1476,20 @@ SubStringRange::iterator SubStringRange::end() {
return SubStringRange::iterator(string_, first_ + length_, no_gc_);
}
void SeqOneByteString::clear_padding() {
const int data_size = SeqString::kHeaderSize + length() * kOneByteSize;
const int padding_size = SizeFor(length()) - data_size;
DCHECK_EQ((DataAndPaddingSizes{data_size, padding_size}),
GetDataAndPaddingSizes());
DCHECK_EQ(address() + data_size + padding_size, address() + Size());
if (padding_size == 0) return;
memset(reinterpret_cast<void*>(address() + data_size), 0, padding_size);
void SeqOneByteString::clear_padding_destructively(int length) {
// Ensure we are not killing the map word, which is already set at this point
static_assert(SizeFor(0) >= kObjectAlignment + kTaggedSize);
memset(
reinterpret_cast<void*>(address() + SizeFor(length) - kObjectAlignment),
0, kObjectAlignment);
}
void SeqTwoByteString::clear_padding() {
const int data_size = SeqString::kHeaderSize + length() * base::kUC16Size;
const int padding_size = SizeFor(length()) - data_size;
DCHECK_EQ((DataAndPaddingSizes{data_size, padding_size}),
GetDataAndPaddingSizes());
DCHECK_EQ(address() + data_size + padding_size, address() + Size());
if (padding_size == 0) return;
memset(reinterpret_cast<void*>(address() + data_size), 0, padding_size);
void SeqTwoByteString::clear_padding_destructively(int length) {
// Ensure we are not killing the map word, which is already set at this point
static_assert(SizeFor(0) >= kObjectAlignment + kTaggedSize);
memset(
reinterpret_cast<void*>(address() + SizeFor(length) - kObjectAlignment),
0, kObjectAlignment);
}
// static

View File

@ -1824,7 +1824,7 @@ Handle<String> SeqString::Truncate(Isolate* isolate, Handle<SeqString> string,
// We are storing the new length using release store after creating a filler
// for the left-over space to avoid races with the sweeper thread.
string->set_length(new_length, kReleaseStore);
string->clear_padding();
string->ClearPadding();
return string;
}
@ -1850,11 +1850,11 @@ SeqString::DataAndPaddingSizes SeqTwoByteString::GetDataAndPaddingSizes()
return DataAndPaddingSizes{data_size, padding_size};
}
void SeqString::clear_padding() {
if (IsSeqOneByteString()) {
return SeqOneByteString::cast(*this).clear_padding();
}
return SeqTwoByteString::cast(*this).clear_padding();
void SeqString::ClearPadding() {
DataAndPaddingSizes sz = GetDataAndPaddingSizes();
DCHECK_EQ(address() + sz.data_size + sz.padding_size, address() + Size());
if (sz.padding_size == 0) return;
memset(reinterpret_cast<void*>(address() + sz.data_size), 0, sz.padding_size);
}
uint16_t ConsString::Get(

View File

@ -714,8 +714,8 @@ class SeqString : public TorqueGeneratedSeqString<SeqString, String> {
};
DataAndPaddingSizes GetDataAndPaddingSizes() const;
// Zero out the padding bytes of this string.
void clear_padding();
// Zero out only the padding bytes of this string.
void ClearPadding();
TQ_OBJECT_CONSTRUCTORS(SeqString)
};
@ -761,8 +761,8 @@ class SeqOneByteString
DataAndPaddingSizes GetDataAndPaddingSizes() const;
// Zero out the padding bytes of this string.
inline void clear_padding();
// Initializes padding bytes. Potentially zeros tail of the payload too!
inline void clear_padding_destructively(int length);
// Maximal memory usage for a single sequential one-byte string.
static const int kMaxCharsSize = kMaxLength;
@ -808,8 +808,8 @@ class SeqTwoByteString
DataAndPaddingSizes GetDataAndPaddingSizes() const;
// Zero out the padding bytes of this string.
inline void clear_padding();
// Initializes padding bytes. Potentially zeros tail of the payload too!
inline void clear_padding_destructively(int length);
// Maximal memory usage for a single sequential two-byte string.
static const int kMaxCharsSize = kMaxLength * 2;