Reland "[heap] pre-populate the single_character_string_cache"
This is a reland of commit 07e11a64e4
.
The original change removed the fill_thehole_and_call_runtime bailout
in StringBuiltinsAssembler::StringToArray() so when the string
is external and cannot be unpacked, the FixedArray won't be filled
with holes before we call into the runtime, thus failing a
heap verification if a GC happens before the array is filled. This
reland adds back the bailout for this case.
Bug: v8:12718, chromium:1330410
Original change's description:
> [heap] pre-populate the single_character_string_cache
>
> This simplifies the code and removes the runtime overhead of
> spontaneously adding strings to the cache.
>
> Bug: v8:12718
> Change-Id: I2ed49bd82e3baf2563eeb8f463be72c0308c52c5
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3616553
> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Commit-Queue: Joyee Cheung <joyee@igalia.com>
> Cr-Commit-Position: refs/heads/main@{#80803}
Change-Id: I25e8724d511a8d0d971fa2a9b6ba8a0eafce4413
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3793525
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82082}
This commit is contained in:
parent
d6e2554d11
commit
c0690fa8f0
@ -1269,7 +1269,7 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray(
|
||||
TNode<RawPtrT> string_data =
|
||||
to_direct.PointerToData(&fill_thehole_and_call_runtime);
|
||||
TNode<IntPtrT> string_data_offset = to_direct.offset();
|
||||
TNode<FixedArray> cache = SingleCharacterStringCacheConstant();
|
||||
TNode<FixedArray> cache = SingleCharacterStringTableConstant();
|
||||
|
||||
BuildFastLoop<IntPtrT>(
|
||||
IntPtrConstant(0), length,
|
||||
@ -1285,9 +1285,7 @@ TNode<JSArray> StringBuiltinsAssembler::StringToArray(
|
||||
TNode<UintPtrT> code_index = ChangeUint32ToWord(char_code);
|
||||
TNode<Object> entry = LoadFixedArrayElement(cache, code_index);
|
||||
|
||||
// If we cannot find a char in the cache, fill the hole for the fixed
|
||||
// array, and call runtime.
|
||||
GotoIf(IsUndefined(entry), &fill_thehole_and_call_runtime);
|
||||
CSA_DCHECK(this, Word32BinaryNot(IsUndefined(entry)));
|
||||
|
||||
StoreFixedArrayElement(elements, index, entry);
|
||||
},
|
||||
|
@ -7063,34 +7063,15 @@ TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) {
|
||||
BIND(&if_codeisonebyte);
|
||||
{
|
||||
// Load the isolate wide single character string cache.
|
||||
TNode<FixedArray> cache = SingleCharacterStringCacheConstant();
|
||||
TNode<FixedArray> cache = SingleCharacterStringTableConstant();
|
||||
TNode<IntPtrT> code_index = Signed(ChangeUint32ToWord(code));
|
||||
|
||||
// Check if we have an entry for the {code} in the single character string
|
||||
// cache already.
|
||||
Label if_entryisundefined(this, Label::kDeferred),
|
||||
if_entryisnotundefined(this);
|
||||
TNode<Object> entry = UnsafeLoadFixedArrayElement(cache, code_index);
|
||||
Branch(IsUndefined(entry), &if_entryisundefined, &if_entryisnotundefined);
|
||||
CSA_DCHECK(this, Word32BinaryNot(IsUndefined(entry)));
|
||||
|
||||
BIND(&if_entryisundefined);
|
||||
{
|
||||
// Allocate a new SeqOneByteString for {code} and store it in the {cache}.
|
||||
TNode<String> result = AllocateSeqOneByteString(1);
|
||||
StoreNoWriteBarrier(
|
||||
MachineRepresentation::kWord8, result,
|
||||
IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), code);
|
||||
StoreFixedArrayElement(cache, code_index, result);
|
||||
var_result = result;
|
||||
Goto(&if_done);
|
||||
}
|
||||
|
||||
BIND(&if_entryisnotundefined);
|
||||
{
|
||||
// Return the entry from the {cache}.
|
||||
var_result = CAST(entry);
|
||||
Goto(&if_done);
|
||||
}
|
||||
// Return the entry from the {cache}.
|
||||
var_result = CAST(entry);
|
||||
Goto(&if_done);
|
||||
}
|
||||
|
||||
BIND(&if_codeistwobyte);
|
||||
|
@ -120,8 +120,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(ShadowRealmImportValueFulfilledSFI, \
|
||||
shadow_realm_import_value_fulfilled_sfi, \
|
||||
ShadowRealmImportValueFulfilledSFI) \
|
||||
V(SingleCharacterStringCache, single_character_string_cache, \
|
||||
SingleCharacterStringCache) \
|
||||
V(SingleCharacterStringTable, single_character_string_table, \
|
||||
SingleCharacterStringTable) \
|
||||
V(StringIteratorProtector, string_iterator_protector, \
|
||||
StringIteratorProtector) \
|
||||
V(TypedArraySpeciesProtector, typed_array_species_protector, \
|
||||
|
@ -4037,7 +4037,6 @@ Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
|
||||
Node* code = __ Word32And(value, __ Uint32Constant(0xFFFF));
|
||||
|
||||
auto if_not_one_byte = __ MakeDeferredLabel();
|
||||
auto cache_miss = __ MakeDeferredLabel();
|
||||
auto done = __ MakeLabel(MachineRepresentation::kTagged);
|
||||
|
||||
// Check if the {code} is a one byte character
|
||||
@ -4045,46 +4044,19 @@ Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
|
||||
code, __ Uint32Constant(String::kMaxOneByteCharCode));
|
||||
__ GotoIfNot(check1, &if_not_one_byte);
|
||||
{
|
||||
// Load the isolate wide single character string cache.
|
||||
Node* cache = __ HeapConstant(factory()->single_character_string_cache());
|
||||
// Load the isolate wide single character string table.
|
||||
Node* table = __ HeapConstant(factory()->single_character_string_table());
|
||||
|
||||
// Compute the {cache} index for {code}.
|
||||
// Compute the {table} index for {code}.
|
||||
Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code);
|
||||
|
||||
// Check if we have an entry for the {code} in the single character string
|
||||
// cache already.
|
||||
// Load the string for the {code} from the single character string
|
||||
// table.
|
||||
Node* entry =
|
||||
__ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
|
||||
__ LoadElement(AccessBuilder::ForFixedArrayElement(), table, index);
|
||||
|
||||
Node* check2 = __ TaggedEqual(entry, __ UndefinedConstant());
|
||||
__ GotoIf(check2, &cache_miss);
|
||||
|
||||
// Use the {entry} from the {cache}.
|
||||
// Use the {entry} from the {table}.
|
||||
__ Goto(&done, entry);
|
||||
|
||||
__ Bind(&cache_miss);
|
||||
{
|
||||
// Allocate a new SeqOneByteString for {code}.
|
||||
Node* vtrue2 =
|
||||
__ Allocate(AllocationType::kYoung,
|
||||
__ IntPtrConstant(SeqOneByteString::SizeFor(1)));
|
||||
__ StoreField(AccessBuilder::ForMap(), vtrue2,
|
||||
__ HeapConstant(factory()->one_byte_string_map()));
|
||||
__ StoreField(AccessBuilder::ForNameRawHashField(), vtrue2,
|
||||
__ Int32Constant(Name::kEmptyHashField));
|
||||
__ StoreField(AccessBuilder::ForStringLength(), vtrue2,
|
||||
__ Int32Constant(1));
|
||||
__ Store(
|
||||
StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
|
||||
vtrue2,
|
||||
__ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag),
|
||||
code);
|
||||
|
||||
// Remember it in the {cache}.
|
||||
__ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index,
|
||||
vtrue2);
|
||||
__ Goto(&done, vtrue2);
|
||||
}
|
||||
}
|
||||
|
||||
__ Bind(&if_not_one_byte);
|
||||
@ -4156,7 +4128,6 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
|
||||
|
||||
auto if_not_single_code = __ MakeDeferredLabel();
|
||||
auto if_not_one_byte = __ MakeDeferredLabel();
|
||||
auto cache_miss = __ MakeDeferredLabel();
|
||||
auto done = __ MakeLabel(MachineRepresentation::kTagged);
|
||||
|
||||
// Check if the {code} is a single code unit
|
||||
@ -4169,46 +4140,19 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
|
||||
code, __ Uint32Constant(String::kMaxOneByteCharCode));
|
||||
__ GotoIfNot(check1, &if_not_one_byte);
|
||||
{
|
||||
// Load the isolate wide single character string cache.
|
||||
Node* cache = __ HeapConstant(factory()->single_character_string_cache());
|
||||
// Load the isolate wide single character string table.
|
||||
Node* table = __ HeapConstant(factory()->single_character_string_table());
|
||||
|
||||
// Compute the {cache} index for {code}.
|
||||
// Compute the {table} index for {code}.
|
||||
Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code);
|
||||
|
||||
// Check if we have an entry for the {code} in the single character string
|
||||
// cache already.
|
||||
// Load the string for the {code} from the single character string
|
||||
// table.
|
||||
Node* entry =
|
||||
__ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
|
||||
__ LoadElement(AccessBuilder::ForFixedArrayElement(), table, index);
|
||||
|
||||
Node* check2 = __ TaggedEqual(entry, __ UndefinedConstant());
|
||||
__ GotoIf(check2, &cache_miss);
|
||||
|
||||
// Use the {entry} from the {cache}.
|
||||
// Use the {entry} from the {table}.
|
||||
__ Goto(&done, entry);
|
||||
|
||||
__ Bind(&cache_miss);
|
||||
{
|
||||
// Allocate a new SeqOneByteString for {code}.
|
||||
Node* vtrue2 =
|
||||
__ Allocate(AllocationType::kYoung,
|
||||
__ IntPtrConstant(SeqOneByteString::SizeFor(1)));
|
||||
__ StoreField(AccessBuilder::ForMap(), vtrue2,
|
||||
__ HeapConstant(factory()->one_byte_string_map()));
|
||||
__ StoreField(AccessBuilder::ForNameRawHashField(), vtrue2,
|
||||
__ Int32Constant(Name::kEmptyHashField));
|
||||
__ StoreField(AccessBuilder::ForStringLength(), vtrue2,
|
||||
__ Int32Constant(1));
|
||||
__ Store(
|
||||
StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
|
||||
vtrue2,
|
||||
__ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag),
|
||||
code);
|
||||
|
||||
// Remember it in the {cache}.
|
||||
__ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index,
|
||||
vtrue2);
|
||||
__ Goto(&done, vtrue2);
|
||||
}
|
||||
}
|
||||
|
||||
__ Bind(&if_not_one_byte);
|
||||
|
@ -1060,18 +1060,10 @@ StringTransitionStrategy Factory::ComputeSharingStrategyForString(
|
||||
|
||||
Handle<String> Factory::LookupSingleCharacterStringFromCode(uint16_t code) {
|
||||
if (code <= unibrow::Latin1::kMaxChar) {
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
Object value = single_character_string_cache()->get(code);
|
||||
if (value != *undefined_value()) {
|
||||
return handle(String::cast(value), isolate());
|
||||
}
|
||||
}
|
||||
uint8_t buffer[] = {static_cast<uint8_t>(code)};
|
||||
Handle<String> result =
|
||||
InternalizeString(base::Vector<const uint8_t>(buffer, 1));
|
||||
single_character_string_cache()->set(code, *result);
|
||||
return result;
|
||||
DisallowGarbageCollection no_gc;
|
||||
Object value = single_character_string_table()->get(code);
|
||||
DCHECK_NE(value, *undefined_value());
|
||||
return handle(String::cast(value), isolate());
|
||||
}
|
||||
uint16_t buffer[] = {code};
|
||||
return InternalizeString(base::Vector<const uint16_t>(buffer, 1));
|
||||
|
@ -813,8 +813,8 @@ void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
|
||||
RecordSimpleVirtualObjectStats(HeapObject(), heap_->number_string_cache(),
|
||||
ObjectStats::NUMBER_STRING_CACHE_TYPE);
|
||||
RecordSimpleVirtualObjectStats(
|
||||
HeapObject(), heap_->single_character_string_cache(),
|
||||
ObjectStats::SINGLE_CHARACTER_STRING_CACHE_TYPE);
|
||||
HeapObject(), heap_->single_character_string_table(),
|
||||
ObjectStats::SINGLE_CHARACTER_STRING_TABLE_TYPE);
|
||||
RecordSimpleVirtualObjectStats(HeapObject(), heap_->string_split_cache(),
|
||||
ObjectStats::STRING_SPLIT_CACHE_TYPE);
|
||||
RecordSimpleVirtualObjectStats(HeapObject(), heap_->regexp_multiple_cache(),
|
||||
|
@ -76,7 +76,7 @@
|
||||
V(SCRIPT_SOURCE_NON_EXTERNAL_ONE_BYTE_TYPE) \
|
||||
V(SCRIPT_SOURCE_NON_EXTERNAL_TWO_BYTE_TYPE) \
|
||||
V(SERIALIZED_OBJECTS_TYPE) \
|
||||
V(SINGLE_CHARACTER_STRING_CACHE_TYPE) \
|
||||
V(SINGLE_CHARACTER_STRING_TABLE_TYPE) \
|
||||
V(STRING_SPLIT_CACHE_TYPE) \
|
||||
V(STRING_EXTERNAL_RESOURCE_ONE_BYTE_TYPE) \
|
||||
V(STRING_EXTERNAL_RESOURCE_TWO_BYTE_TYPE) \
|
||||
|
@ -686,9 +686,17 @@ void Heap::CreateInitialObjects() {
|
||||
|
||||
set_weak_refs_keep_during_job(roots.undefined_value());
|
||||
|
||||
// Allocate cache for single character one byte strings.
|
||||
set_single_character_string_cache(*factory->NewFixedArray(
|
||||
String::kMaxOneByteCharCode + 1, AllocationType::kOld));
|
||||
// Allocate and initialize table for single character one byte strings.
|
||||
int table_size = String::kMaxOneByteCharCode + 1;
|
||||
set_single_character_string_table(
|
||||
*factory->NewFixedArray(table_size, AllocationType::kOld));
|
||||
for (int i = 0; i < table_size; ++i) {
|
||||
uint8_t code = static_cast<uint8_t>(i);
|
||||
Handle<String> str =
|
||||
factory->InternalizeString(base::Vector<const uint8_t>(&code, 1));
|
||||
DCHECK(ReadOnlyHeap::Contains(*str));
|
||||
single_character_string_table().set(i, *str);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < arraysize(constant_string_table); i++) {
|
||||
Handle<String> str =
|
||||
|
@ -50,7 +50,7 @@ namespace internal {
|
||||
V(SCRIPT_LIST_SUB_TYPE) \
|
||||
V(SERIALIZED_OBJECTS_SUB_TYPE) \
|
||||
V(SHARED_FUNCTION_INFOS_SUB_TYPE) \
|
||||
V(SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE) \
|
||||
V(SINGLE_CHARACTER_STRING_TABLE_SUB_TYPE) \
|
||||
V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE) \
|
||||
V(STRING_SPLIT_CACHE_SUB_TYPE) \
|
||||
V(TEMPLATE_INFO_SUB_TYPE) \
|
||||
|
@ -1543,7 +1543,7 @@ ConcurrentLookupIterator::TryGetOwnConstantElement(
|
||||
// - elements[i] (immutable if constant; be careful around dictionaries).
|
||||
// - holder.AsJSPrimitiveWrapper.value.AsString.length (immutable).
|
||||
// - holder.AsJSPrimitiveWrapper.value.AsString[i] (immutable).
|
||||
// - single_character_string_cache()->get().
|
||||
// - single_character_string_table()->get().
|
||||
|
||||
if (IsFrozenElementsKind(elements_kind)) {
|
||||
if (!elements.IsFixedArray()) return kGaveUp;
|
||||
@ -1612,9 +1612,10 @@ ConcurrentLookupIterator::Result ConcurrentLookupIterator::TryGetOwnChar(
|
||||
|
||||
if (charcode > unibrow::Latin1::kMaxChar) return kGaveUp;
|
||||
|
||||
Object value = isolate->factory()->single_character_string_cache()->get(
|
||||
Object value = isolate->factory()->single_character_string_table()->get(
|
||||
charcode, kRelaxedLoad);
|
||||
if (value == ReadOnlyRoots(isolate).undefined_value()) return kGaveUp;
|
||||
|
||||
DCHECK_NE(value, ReadOnlyRoots(isolate).undefined_value());
|
||||
|
||||
*result_out = String::cast(value);
|
||||
return kPresent;
|
||||
|
@ -243,9 +243,10 @@ class Symbol;
|
||||
V(PropertyCell, set_iterator_protector, SetIteratorProtector) \
|
||||
V(PropertyCell, string_iterator_protector, StringIteratorProtector) \
|
||||
/* Caches */ \
|
||||
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
|
||||
V(FixedArray, string_split_cache, StringSplitCache) \
|
||||
V(FixedArray, regexp_multiple_cache, RegExpMultipleCache) \
|
||||
/* Table of strings of one-byte single characters */ \
|
||||
V(FixedArray, single_character_string_table, SingleCharacterStringTable) \
|
||||
/* Indirection lists for isolate-independent builtins */ \
|
||||
V(FixedArray, builtins_constants_table, BuiltinsConstantsTable) \
|
||||
/* Internal SharedFunctionInfos */ \
|
||||
|
@ -263,36 +263,6 @@ RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copies Latin1 characters to the given fixed array looking up
|
||||
// one-char strings in the cache. Gives up on the first char that is
|
||||
// not in the cache and fills the remainder with smi zeros. Returns
|
||||
// the length of the successfully copied prefix.
|
||||
static int CopyCachedOneByteCharsToArray(Heap* heap, const uint8_t* chars,
|
||||
FixedArray elements, int length) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
FixedArray one_byte_cache = heap->single_character_string_cache();
|
||||
Object undefined = ReadOnlyRoots(heap).undefined_value();
|
||||
int i;
|
||||
WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
|
||||
for (i = 0; i < length; ++i) {
|
||||
Object value = one_byte_cache.get(chars[i]);
|
||||
if (value == undefined) break;
|
||||
elements.set(i, value, mode);
|
||||
}
|
||||
if (i < length) {
|
||||
MemsetTagged(elements.RawFieldOfElementAt(i), Smi::zero(), length - i);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (int j = 0; j < length; ++j) {
|
||||
Object element = elements.get(j);
|
||||
DCHECK(element == Smi::zero() ||
|
||||
(element.IsString() && String::cast(element).LooksValid()));
|
||||
}
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
// Converts a String to JSArray.
|
||||
// For example, "foo" => ["f", "o", "o"].
|
||||
RUNTIME_FUNCTION(Runtime_StringToArray) {
|
||||
@ -305,31 +275,28 @@ RUNTIME_FUNCTION(Runtime_StringToArray) {
|
||||
const int length =
|
||||
static_cast<int>(std::min(static_cast<uint32_t>(s->length()), limit));
|
||||
|
||||
Handle<FixedArray> elements;
|
||||
int position = 0;
|
||||
Handle<FixedArray> elements = isolate->factory()->NewFixedArray(length);
|
||||
if (s->IsFlat() && s->IsOneByteRepresentation()) {
|
||||
// Try using cached chars where possible.
|
||||
elements = isolate->factory()->NewFixedArray(length);
|
||||
|
||||
DisallowGarbageCollection no_gc;
|
||||
String::FlatContent content = s->GetFlatContent(no_gc);
|
||||
if (content.IsOneByte()) {
|
||||
base::Vector<const uint8_t> chars = content.ToOneByteVector();
|
||||
// Note, this will initialize all elements (not only the prefix)
|
||||
// to prevent GC from seeing partially initialized array.
|
||||
position = CopyCachedOneByteCharsToArray(isolate->heap(), chars.begin(),
|
||||
*elements, length);
|
||||
} else {
|
||||
MemsetTagged(elements->data_start(),
|
||||
ReadOnlyRoots(isolate).undefined_value(), length);
|
||||
// Use pre-initialized single characters.
|
||||
base::Vector<const uint8_t> chars = content.ToOneByteVector();
|
||||
FixedArray one_byte_table =
|
||||
isolate->heap()->single_character_string_table();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object value = one_byte_table.get(chars[i]);
|
||||
DCHECK(value.IsString());
|
||||
DCHECK(ReadOnlyHeap::Contains(HeapObject::cast(value)));
|
||||
// The single-character strings are in RO space so it should
|
||||
// be safe to skip the write barriers.
|
||||
elements->set(i, value, SKIP_WRITE_BARRIER);
|
||||
}
|
||||
} else {
|
||||
elements = isolate->factory()->NewFixedArray(length);
|
||||
}
|
||||
for (int i = position; i < length; ++i) {
|
||||
Handle<Object> str =
|
||||
isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
|
||||
elements->set(i, *str);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Handle<Object> str =
|
||||
isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i));
|
||||
elements->set(i, *str);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -708,21 +708,19 @@ TEST(MakingExternalOneByteStringConditions) {
|
||||
Local<String> tiny_local_string = v8_str("s");
|
||||
Local<String> local_string = v8_str("s1234");
|
||||
|
||||
// Single-character strings should not be externalized because they
|
||||
// are always in the RO-space.
|
||||
CHECK(!tiny_local_string->CanMakeExternal());
|
||||
if (!v8::internal::FLAG_single_generation) {
|
||||
// We should refuse to externalize new space strings.
|
||||
CHECK(!local_string->CanMakeExternal());
|
||||
// Trigger GCs so that the newly allocated string moves to old gen.
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
|
||||
CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
|
||||
CHECK(!tiny_local_string->CanMakeExternal());
|
||||
}
|
||||
// Old space strings should be accepted.
|
||||
CHECK(local_string->CanMakeExternal());
|
||||
|
||||
// Tiny strings are not in-place externalizable when pointer compression is
|
||||
// enabled, but they are if sandboxed external pointers are enabled.
|
||||
CHECK_EQ(V8_SANDBOXED_EXTERNAL_POINTERS_BOOL ||
|
||||
i::kTaggedSize == i::kSystemPointerSize,
|
||||
tiny_local_string->CanMakeExternal());
|
||||
}
|
||||
|
||||
|
||||
|
@ -778,9 +778,9 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
|
||||
DisableAlwaysOpt();
|
||||
const char* source1 =
|
||||
R"javascript(
|
||||
// String would be internalized if it came from a literal so create "A"
|
||||
// String would be internalized if it came from a literal so create "AB"
|
||||
// via a function call.
|
||||
var global = String.fromCharCode(65);
|
||||
var global = String.fromCharCode(65, 66);
|
||||
function f() { return global; }
|
||||
)javascript";
|
||||
|
||||
@ -801,7 +801,7 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
|
||||
v8::Local<v8::Value> result = CompileRun("f()").As<v8::Value>();
|
||||
CHECK(result->IsString());
|
||||
i::String str = *v8::Utils::OpenHandle(*result.As<v8::String>());
|
||||
CHECK_EQ(std::string(str.ToCString().get()), "A");
|
||||
CHECK_EQ(std::string(str.ToCString().get()), "AB");
|
||||
CHECK(!str.IsInternalizedString());
|
||||
CHECK(!i::ReadOnlyHeap::Contains(str));
|
||||
}
|
||||
|
@ -504,69 +504,69 @@ KNOWN_OBJECTS = {
|
||||
("read_only_space", 0x03655): "EmptyFunctionScopeInfo",
|
||||
("read_only_space", 0x03679): "NativeScopeInfo",
|
||||
("read_only_space", 0x03691): "HashSeed",
|
||||
("old_space", 0x04231): "ArgumentsIteratorAccessor",
|
||||
("old_space", 0x04259): "ArrayLengthAccessor",
|
||||
("old_space", 0x04281): "BoundFunctionLengthAccessor",
|
||||
("old_space", 0x042a9): "BoundFunctionNameAccessor",
|
||||
("old_space", 0x042d1): "ErrorStackAccessor",
|
||||
("old_space", 0x042f9): "FunctionArgumentsAccessor",
|
||||
("old_space", 0x04321): "FunctionCallerAccessor",
|
||||
("old_space", 0x04349): "FunctionNameAccessor",
|
||||
("old_space", 0x04371): "FunctionLengthAccessor",
|
||||
("old_space", 0x04399): "FunctionPrototypeAccessor",
|
||||
("old_space", 0x043c1): "SharedArrayLengthAccessor",
|
||||
("old_space", 0x043e9): "StringLengthAccessor",
|
||||
("old_space", 0x04411): "ValueUnavailableAccessor",
|
||||
("old_space", 0x04439): "WrappedFunctionLengthAccessor",
|
||||
("old_space", 0x04461): "WrappedFunctionNameAccessor",
|
||||
("old_space", 0x04489): "InvalidPrototypeValidityCell",
|
||||
("old_space", 0x04491): "EmptyScript",
|
||||
("old_space", 0x044d5): "ManyClosuresCell",
|
||||
("old_space", 0x044e1): "ArrayConstructorProtector",
|
||||
("old_space", 0x044f5): "NoElementsProtector",
|
||||
("old_space", 0x04509): "MegaDOMProtector",
|
||||
("old_space", 0x0451d): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x04531): "ArraySpeciesProtector",
|
||||
("old_space", 0x04545): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x04559): "PromiseSpeciesProtector",
|
||||
("old_space", 0x0456d): "RegExpSpeciesProtector",
|
||||
("old_space", 0x04581): "StringLengthProtector",
|
||||
("old_space", 0x04595): "ArrayIteratorProtector",
|
||||
("old_space", 0x045a9): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x045bd): "PromiseHookProtector",
|
||||
("old_space", 0x045d1): "PromiseResolveProtector",
|
||||
("old_space", 0x045e5): "MapIteratorProtector",
|
||||
("old_space", 0x045f9): "PromiseThenProtector",
|
||||
("old_space", 0x0460d): "SetIteratorProtector",
|
||||
("old_space", 0x04621): "StringIteratorProtector",
|
||||
("old_space", 0x04635): "SingleCharacterStringCache",
|
||||
("old_space", 0x04a3d): "StringSplitCache",
|
||||
("old_space", 0x04e45): "RegExpMultipleCache",
|
||||
("old_space", 0x0524d): "BuiltinsConstantsTable",
|
||||
("old_space", 0x0568d): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x056b1): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x056d5): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x056f9): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x0571d): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x05741): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05765): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x05789): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x057ad): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x057d1): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x057f5): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x05819): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x0583d): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x05861): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05885): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x058a9): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x058cd): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x058f1): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x05915): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x05939): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x0595d): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x05981): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x059a5): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x059c9): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
("old_space", 0x04221): "ArgumentsIteratorAccessor",
|
||||
("old_space", 0x04249): "ArrayLengthAccessor",
|
||||
("old_space", 0x04271): "BoundFunctionLengthAccessor",
|
||||
("old_space", 0x04299): "BoundFunctionNameAccessor",
|
||||
("old_space", 0x042c1): "ErrorStackAccessor",
|
||||
("old_space", 0x042e9): "FunctionArgumentsAccessor",
|
||||
("old_space", 0x04311): "FunctionCallerAccessor",
|
||||
("old_space", 0x04339): "FunctionNameAccessor",
|
||||
("old_space", 0x04361): "FunctionLengthAccessor",
|
||||
("old_space", 0x04389): "FunctionPrototypeAccessor",
|
||||
("old_space", 0x043b1): "SharedArrayLengthAccessor",
|
||||
("old_space", 0x043d9): "StringLengthAccessor",
|
||||
("old_space", 0x04401): "ValueUnavailableAccessor",
|
||||
("old_space", 0x04429): "WrappedFunctionLengthAccessor",
|
||||
("old_space", 0x04451): "WrappedFunctionNameAccessor",
|
||||
("old_space", 0x04479): "InvalidPrototypeValidityCell",
|
||||
("old_space", 0x04481): "EmptyScript",
|
||||
("old_space", 0x044c5): "ManyClosuresCell",
|
||||
("old_space", 0x044d1): "ArrayConstructorProtector",
|
||||
("old_space", 0x044e5): "NoElementsProtector",
|
||||
("old_space", 0x044f9): "MegaDOMProtector",
|
||||
("old_space", 0x0450d): "IsConcatSpreadableProtector",
|
||||
("old_space", 0x04521): "ArraySpeciesProtector",
|
||||
("old_space", 0x04535): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x04549): "PromiseSpeciesProtector",
|
||||
("old_space", 0x0455d): "RegExpSpeciesProtector",
|
||||
("old_space", 0x04571): "StringLengthProtector",
|
||||
("old_space", 0x04585): "ArrayIteratorProtector",
|
||||
("old_space", 0x04599): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x045ad): "PromiseHookProtector",
|
||||
("old_space", 0x045c1): "PromiseResolveProtector",
|
||||
("old_space", 0x045d5): "MapIteratorProtector",
|
||||
("old_space", 0x045e9): "PromiseThenProtector",
|
||||
("old_space", 0x045fd): "SetIteratorProtector",
|
||||
("old_space", 0x04611): "StringIteratorProtector",
|
||||
("old_space", 0x04625): "StringSplitCache",
|
||||
("old_space", 0x04a2d): "RegExpMultipleCache",
|
||||
("old_space", 0x04e35): "SingleCharacterStringTable",
|
||||
("old_space", 0x0523d): "BuiltinsConstantsTable",
|
||||
("old_space", 0x0567d): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x056a1): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x056c5): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x056e9): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x0570d): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x05731): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05755): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x05779): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x0579d): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x057c1): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x057e5): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x05809): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x0582d): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x05851): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05875): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x05899): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x058bd): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x058e1): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x05905): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x05929): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x0594d): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x05971): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x05995): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x059b9): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user