[string-iswellformed] Implement String#{is,to}WellFormed

Bug: v8:13557
Change-Id: I6fa772c70d8307eca047fd839058279ce244f0e0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4118066
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85002}
This commit is contained in:
Shu-yu Guo 2022-12-22 09:19:20 -08:00 committed by V8 LUCI CQ
parent c74a6cd257
commit 5c7fca4a61
20 changed files with 355 additions and 41 deletions

View File

@ -861,6 +861,7 @@ filegroup(
"src/builtins/string-html.tq",
"src/builtins/string-includes.tq",
"src/builtins/string-indexof.tq",
"src/builtins/string-iswellformed.tq",
"src/builtins/string-iterator.tq",
"src/builtins/string-match-search.tq",
"src/builtins/string-pad.tq",
@ -870,6 +871,7 @@ filegroup(
"src/builtins/string-startswith.tq",
"src/builtins/string-substr.tq",
"src/builtins/string-substring.tq",
"src/builtins/string-towellformed.tq",
"src/builtins/string-trim.tq",
"src/builtins/symbol.tq",
"src/builtins/torque-internal.tq",

View File

@ -1801,6 +1801,7 @@ torque_files = [
"src/builtins/string-html.tq",
"src/builtins/string-includes.tq",
"src/builtins/string-indexof.tq",
"src/builtins/string-iswellformed.tq",
"src/builtins/string-iterator.tq",
"src/builtins/string-match-search.tq",
"src/builtins/string-pad.tq",
@ -1810,6 +1811,7 @@ torque_files = [
"src/builtins/string-startswith.tq",
"src/builtins/string-substr.tq",
"src/builtins/string-substring.tq",
"src/builtins/string-towellformed.tq",
"src/builtins/string-trim.tq",
"src/builtins/symbol.tq",
"src/builtins/torque-internal.tq",

View File

@ -1492,6 +1492,61 @@ TNode<Int32T> StringBuiltinsAssembler::LoadSurrogatePairAt(
return var_result.value();
}
TNode<BoolT> StringBuiltinsAssembler::HasUnpairedSurrogate(TNode<String> string,
Label* if_indirect) {
TNode<Uint16T> instance_type = LoadInstanceType(string);
CSA_DCHECK(this, Word32Equal(Word32And(instance_type,
Int32Constant(kStringEncodingMask)),
Int32Constant(kTwoByteStringTag)));
GotoIfNot(Word32Equal(Word32And(instance_type,
Int32Constant(kIsIndirectStringMask |
kUncachedExternalStringMask)),
Int32Constant(0)),
if_indirect);
TNode<RawPtrT> string_data = DirectStringData(string, instance_type);
TNode<IntPtrT> length = LoadStringLengthAsWord(string);
const TNode<ExternalReference> has_unpaired_surrogate =
ExternalConstant(ExternalReference::has_unpaired_surrogate());
return UncheckedCast<BoolT>(
CallCFunction(has_unpaired_surrogate, MachineType::Uint32(),
std::make_pair(MachineType::Pointer(), string_data),
std::make_pair(MachineType::IntPtr(), length)));
}
void StringBuiltinsAssembler::ReplaceUnpairedSurrogates(TNode<String> source,
TNode<String> dest,
Label* if_indirect) {
TNode<Uint16T> source_instance_type = LoadInstanceType(source);
CSA_DCHECK(this, Word32Equal(Word32And(source_instance_type,
Int32Constant(kStringEncodingMask)),
Int32Constant(kTwoByteStringTag)));
GotoIfNot(Word32Equal(Word32And(source_instance_type,
Int32Constant(kIsIndirectStringMask |
kUncachedExternalStringMask)),
Int32Constant(0)),
if_indirect);
TNode<RawPtrT> source_data = DirectStringData(source, source_instance_type);
// The destination string is a freshly allocated SeqString, and so is always
// direct.
TNode<Uint16T> dest_instance_type = LoadInstanceType(dest);
CSA_DCHECK(this, Word32Equal(Word32And(dest_instance_type,
Int32Constant(kStringEncodingMask)),
Int32Constant(kTwoByteStringTag)));
TNode<RawPtrT> dest_data = DirectStringData(dest, dest_instance_type);
TNode<IntPtrT> length = LoadStringLengthAsWord(source);
CSA_DCHECK(this, IntPtrEqual(length, LoadStringLengthAsWord(dest)));
const TNode<ExternalReference> replace_unpaired_surrogates =
ExternalConstant(ExternalReference::replace_unpaired_surrogates());
CallCFunction(replace_unpaired_surrogates, MachineType::Pointer(),
std::make_pair(MachineType::Pointer(), source_data),
std::make_pair(MachineType::Pointer(), dest_data),
std::make_pair(MachineType::IntPtr(), length));
}
void StringBuiltinsAssembler::BranchIfStringPrimitiveWithNoCustomIteration(
TNode<Object> object, TNode<Context> context, Label* if_true,
Label* if_false) {

View File

@ -33,6 +33,10 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
TNode<Int32T> LoadSurrogatePairAt(TNode<String> string, TNode<IntPtrT> length,
TNode<IntPtrT> index,
UnicodeEncoding encoding);
TNode<BoolT> HasUnpairedSurrogate(TNode<String> string, Label* if_indirect);
void ReplaceUnpairedSurrogates(TNode<String> source, TNode<String> dest,
Label* if_indirect);
TNode<String> StringFromSingleUTF16EncodedCodePoint(TNode<Int32T> codepoint);

View File

@ -0,0 +1,45 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include 'src/builtins/builtins-string-gen.h'
namespace runtime {
extern runtime StringIsWellFormed(Context, String): Boolean;
}
namespace string {
extern macro StringBuiltinsAssembler::HasUnpairedSurrogate(String):
bool labels Indirect;
transitioning javascript builtin
StringPrototypeIsWellFormed(
js-implicit context: NativeContext,
receiver: JSAny)(...arguments): Boolean {
const methodName: constexpr string = 'String.prototype.isWellFormed';
// 1. Let O be ? RequireObjectCoercible(this value).
// 2. Let S be ? ToString(O).
const s = ToThisString(receiver, methodName);
// 3. Return IsStringWellFormedUnicode(S).
// Fast path: one-byte strings cannot have unpaired surrogates and are
// definitionally well-formed.
if (s.StringInstanceType().is_one_byte) return True;
// Slow path: flatten the string and look for unpaired surrogates.
//
// TODO(v8:13557): The two-byte case can be optimized by extending the
// InstanceType. See
// https://docs.google.com/document/d/15f-1c_Ysw3lvjy_Gx0SmmD9qeO8UuXuAbWIpWCnTDO8/
const flat = Flatten(s);
try {
const illFormed = HasUnpairedSurrogate(flat) otherwise Indirect;
return illFormed ? False : True;
} label Indirect deferred {
return runtime::StringIsWellFormed(context, flat);
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include 'src/builtins/builtins-string-gen.h'
namespace runtime {
extern runtime StringToWellFormed(Context, String): String;
}
namespace string {
extern macro StringBuiltinsAssembler::ReplaceUnpairedSurrogates(
String, String): void labels Indirect;
transitioning javascript builtin
StringPrototypeToWellFormed(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
const methodName: constexpr string = 'String.prototype.toWellFormed';
// 1. Let O be ? RequireObjectCoercible(this value).
// 2. Let S be ? ToString(O).
const s = ToThisString(receiver, methodName);
// Fast path: one-byte strings cannot have unpaired surrogates and are
// definitionally well-formed.
if (s.StringInstanceType().is_one_byte) return s;
// 3. Let strLen be the length of S.
const strLen = s.length_uint32;
// 4. Let k be 0.
// 5. Let result be the empty String.
const flat = Flatten(s);
let result = flat;
// 6. Repeat, while k < strLen,
// a. Let cp be CodePointAt(S, k).
// b. If cp.[[IsUnpairedSurrogate]] is true, then
// i. Set result to the string-concatenation of result and
// 0xFFFD (REPLACEMENT CHARACTER).
// c. Else,
// i. Set result to the string-concatenation of result and
// UTF16EncodeCodePoint(cp.[[CodePoint]]).
// d. Set k to k + cp.[[CodeUnitCount]].
try {
const illFormed = HasUnpairedSurrogate(flat) otherwise Indirect;
if (illFormed) {
result = AllocateSeqTwoByteString(strLen);
ReplaceUnpairedSurrogates(flat, result) otherwise Indirect;
}
// 7. Return result.
return result;
} label Indirect deferred {
return runtime::StringToWellFormed(context, flat);
}
}
}

View File

@ -36,6 +36,7 @@
#include "src/regexp/regexp-macro-assembler-arch.h"
#include "src/regexp/regexp-stack.h"
#include "src/strings/string-search.h"
#include "src/strings/unicode-inl.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-external-refs.h"
@ -1153,6 +1154,24 @@ static Address LexicographicCompareWrapper(Isolate* isolate, Address smi_x,
FUNCTION_REFERENCE(smi_lexicographic_compare_function,
LexicographicCompareWrapper)
uint32_t HasUnpairedSurrogate(const uint16_t* code_units, size_t length) {
// Use uint32_t to avoid complexity around bool return types.
static constexpr uint32_t kTrue = 1;
static constexpr uint32_t kFalse = 0;
return unibrow::Utf16::HasUnpairedSurrogate(code_units, length) ? kTrue
: kFalse;
}
FUNCTION_REFERENCE(has_unpaired_surrogate, HasUnpairedSurrogate)
void ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
uint16_t* dest_code_units, size_t length) {
return unibrow::Utf16::ReplaceUnpairedSurrogates(source_code_units,
dest_code_units, length);
}
FUNCTION_REFERENCE(replace_unpaired_surrogates, ReplaceUnpairedSurrogates)
FUNCTION_REFERENCE(mutable_big_int_absolute_add_and_canonicalize_function,
MutableBigInt_AbsoluteAddAndCanonicalize)

View File

@ -231,6 +231,8 @@ class StatsCounter;
V(array_indexof_includes_smi_or_object, \
"array_indexof_includes_smi_or_object") \
V(array_indexof_includes_double, "array_indexof_includes_double") \
V(has_unpaired_surrogate, "Utf16::HasUnpairedSurrogate") \
V(replace_unpaired_surrogates, "Utf16::ReplaceUnpairedSurrogates") \
V(try_string_to_index_or_lookup_existing, \
"try_string_to_index_or_lookup_existing") \
V(string_from_forward_table, "string_from_forward_table") \

View File

@ -235,7 +235,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
V(harmony_rab_gsab, \
"harmony ResizableArrayBuffer / GrowableSharedArrayBuffer") \
V(harmony_rab_gsab_transfer, "harmony ArrayBuffer.transfer") \
V(harmony_array_grouping, "harmony array grouping")
V(harmony_array_grouping, "harmony array grouping") \
V(harmony_string_is_well_formed, "harmony String#{is,to}WellFormed")
DEFINE_IMPLICATION(harmony_rab_gsab_transfer, harmony_rab_gsab)

View File

@ -4892,6 +4892,18 @@ void Genesis::InitializeGlobal_harmony_rab_gsab() {
Builtin::kSharedArrayBufferPrototypeGrow, 1, true);
}
void Genesis::InitializeGlobal_harmony_string_is_well_formed() {
if (!v8_flags.harmony_string_is_well_formed) return;
Handle<JSFunction> string_function(native_context()->string_function(),
isolate());
Handle<JSObject> string_prototype(
JSObject::cast(string_function->initial_map().prototype()), isolate());
SimpleInstallFunction(isolate(), string_prototype, "isWellFormed",
Builtin::kStringPrototypeIsWellFormed, 0, false);
SimpleInstallFunction(isolate(), string_prototype, "toWellFormed",
Builtin::kStringPrototypeToWellFormed, 0, false);
}
void Genesis::InitializeGlobal_harmony_temporal() {
if (!v8_flags.harmony_temporal) return;
// -- T e m p o r a l

View File

@ -18,6 +18,7 @@
#include "src/sandbox/external-pointer-inl.h"
#include "src/sandbox/external-pointer.h"
#include "src/strings/string-hasher-inl.h"
#include "src/strings/unicode-inl.h"
#include "src/utils/utils.h"
// Has to be the last include (doesn't have include guards):
@ -956,6 +957,21 @@ ConsString String::VisitFlat(
}
}
bool String::IsWellFormedUnicode(Isolate* isolate, Handle<String> string) {
// One-byte strings are definitionally well formed and cannot have unpaired
// surrogates.
if (string->IsOneByteRepresentation()) return true;
// TODO(v8:13557): The two-byte case can be optimized by extending the
// InstanceType. See
// https://docs.google.com/document/d/15f-1c_Ysw3lvjy_Gx0SmmD9qeO8UuXuAbWIpWCnTDO8/
string = Flatten(isolate, string);
DCHECK(string->IsTwoByteRepresentation());
DisallowGarbageCollection no_gc;
const uint16_t* data = string->template GetChars<uint16_t>(isolate, no_gc);
return !unibrow::Utf16::HasUnpairedSurrogate(data, string->length());
}
template <>
inline base::Vector<const uint8_t> String::GetCharVector(
const DisallowGarbageCollection& no_gc) {

View File

@ -526,6 +526,10 @@ class String : public TorqueGeneratedString<String, Name> {
PtrComprCageBase cage_base,
const SharedStringAccessGuardIfNeeded&);
// Returns true if this string has no unpaired surrogates and false otherwise.
static inline bool IsWellFormedUnicode(Isolate* isolate,
Handle<String> string);
static inline bool IsAscii(const char* chars, int length) {
return IsAscii(reinterpret_cast<const uint8_t*>(chars), length);
}

View File

@ -10,6 +10,7 @@
#include "src/objects/slots.h"
#include "src/objects/smi.h"
#include "src/strings/string-builder-inl.h"
#include "src/strings/unicode-inl.h"
#if V8_ENABLE_WEBASSEMBLY
// TODO(chromium:1236668): Drop this when the "SaveAndClearThreadInWasmFlag"
@ -471,5 +472,30 @@ RUNTIME_FUNCTION(Runtime_StringEscapeQuotes) {
return *builder.ToString().ToHandleChecked();
}
RUNTIME_FUNCTION(Runtime_StringIsWellFormed) {
HandleScope handle_scope(isolate);
DCHECK_EQ(1, args.length());
Handle<String> string = args.at<String>(0);
return isolate->heap()->ToBoolean(
String::IsWellFormedUnicode(isolate, string));
}
RUNTIME_FUNCTION(Runtime_StringToWellFormed) {
HandleScope handle_scope(isolate);
DCHECK_EQ(1, args.length());
Handle<String> source = args.at<String>(0);
if (String::IsWellFormedUnicode(isolate, source)) return *source;
source = String::Flatten(isolate, source);
const int length = source->length();
Handle<SeqTwoByteString> dest =
isolate->factory()->NewRawTwoByteString(length).ToHandleChecked();
DisallowGarbageCollection no_gc;
const uint16_t* source_data =
source->template GetChars<uint16_t>(isolate, no_gc);
uint16_t* dest_data = dest->GetChars(no_gc);
unibrow::Utf16::ReplaceUnpairedSurrogates(source_data, dest_data, length);
return *dest;
}
} // namespace internal
} // namespace v8

View File

@ -462,13 +462,15 @@ namespace internal {
F(StringEscapeQuotes, 1, 1) \
F(StringGreaterThan, 2, 1) \
F(StringGreaterThanOrEqual, 2, 1) \
F(StringIsWellFormed, 1, 1) \
F(StringLastIndexOf, 2, 1) \
F(StringLessThan, 2, 1) \
F(StringLessThanOrEqual, 2, 1) \
F(StringMaxLength, 0, 1) \
F(StringReplaceOneCharWithString, 3, 1) \
F(StringSubstring, 3, 1) \
F(StringToArray, 2, 1)
F(StringToArray, 2, 1) \
F(StringToWellFormed, 1, 1)
#define FOR_EACH_INTRINSIC_SYMBOL(F, I) \
F(CreatePrivateNameSymbol, 1, 1) \

View File

@ -239,6 +239,37 @@ bool Utf8::ValidateEncoding(const byte* bytes, size_t length) {
return state == State::kAccept;
}
// static
void Utf16::ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
uint16_t* dest_code_units,
size_t length) {
// U+FFFD (REPLACEMENT CHARACTER)
constexpr uint16_t kReplacement = 0xFFFD;
for (size_t i = 0; i < length; i++) {
const uint16_t source_code_unit = source_code_units[i];
const size_t copy_index = i;
uint16_t dest_code_unit = source_code_unit;
if (IsLeadSurrogate(source_code_unit)) {
// The current code unit is a leading surrogate. If it's not followed by a
// trailing surrogate, replace it with the replacement character.
if (i == length - 1 || !IsTrailSurrogate(source_code_units[i + 1])) {
dest_code_unit = kReplacement;
} else {
// Copy the paired trailing surrogate. The paired leading surrogate will
// be copied below.
++i;
dest_code_units[i] = source_code_units[i];
}
} else if (IsTrailSurrogate(source_code_unit)) {
// All paired trailing surrogates are skipped above, so this branch is
// only for those that are unpaired.
dest_code_unit = kReplacement;
}
dest_code_units[copy_index] = dest_code_unit;
}
}
#if V8_ENABLE_WEBASSEMBLY
bool Wtf8::ValidateEncoding(const byte* bytes, size_t length) {
using State = GeneralizedUtf8DfaDecoder::State;

View File

@ -121,7 +121,7 @@ class Utf16 {
// 4 bytes and the 3 bytes that were used to encode the lead surrogate
// can be reclaimed.
static const int kMaxExtraUtf8BytesForOneUtf16CodeUnit = 3;
// One UTF-16 surrogate is endoded (illegally) as 3 UTF-8 bytes.
// One UTF-16 surrogate is encoded (illegally) as 3 UTF-8 bytes.
// The illegality stems from the surrogate not being part of a pair.
static const int kUtf8BytesToCodeASurrogate = 3;
static inline uint16_t LeadSurrogate(uint32_t char_code) {
@ -132,6 +132,10 @@ class Utf16 {
}
static inline bool HasUnpairedSurrogate(const uint16_t* code_units,
size_t length);
static void ReplaceUnpairedSurrogates(const uint16_t* source_code_units,
uint16_t* dest_code_units,
size_t length);
};
class Latin1 {

View File

@ -0,0 +1,42 @@
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-externalize-string --harmony-string-is-well-formed
(function TestIsWellFormed() {
const short2ByteWellFormed = '\u1234';
const short2ByteIllFormed = '\uD83D';
assertTrue(short2ByteWellFormed.isWellFormed());
assertFalse(short2ByteIllFormed.isWellFormed());
try {
// Turn the strings into uncached external strings to hit the slow runtime
// path.
externalizeString(short2ByteWellFormed, true);
externalizeString(short2ByteIllFormed, true);
} catch (e) {}
assertTrue(short2ByteWellFormed.isWellFormed());
assertFalse(short2ByteIllFormed.isWellFormed());
})();
(function TestToWellFormed() {
const short2ByteWellFormed = '\u1234';
const short2ByteIllFormed = '\uD83D';
assertTrue(short2ByteWellFormed.isWellFormed());
assertFalse(short2ByteIllFormed.isWellFormed());
try {
// Turn the strings into uncached external strings to hit the slow runtime
// path.
externalizeString(short2ByteWellFormed, true);
externalizeString(short2ByteIllFormed, true);
} catch (e) {}
assertEquals('\u1234', short2ByteWellFormed.toWellFormed());
// U+FFFD (REPLACEMENT CHARACTER)
assertEquals('\uFFFD', short2ByteIllFormed.toWellFormed());
})();

View File

@ -994,20 +994,6 @@
'language/statements/class/decorator/syntax/valid/class-element-decorator-member-expr-identifier-reference': [FAIL],
'language/statements/class/decorator/syntax/valid/class-element-decorator-parenthesized-expr-identifier-reference': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=13557
'built-ins/String/prototype/isWellFormed/length': [FAIL],
'built-ins/String/prototype/isWellFormed/name': [FAIL],
'built-ins/String/prototype/isWellFormed/prop-desc': [FAIL],
'built-ins/String/prototype/isWellFormed/return-abrupt-from-this': [FAIL],
'built-ins/String/prototype/isWellFormed/returns-boolean': [FAIL],
'built-ins/String/prototype/isWellFormed/to-string': [FAIL],
'built-ins/String/prototype/toWellFormed/length': [FAIL],
'built-ins/String/prototype/toWellFormed/name': [FAIL],
'built-ins/String/prototype/toWellFormed/prop-desc': [FAIL],
'built-ins/String/prototype/toWellFormed/return-abrupt-from-this': [FAIL],
'built-ins/String/prototype/toWellFormed/returns-well-formed-string': [FAIL],
'built-ins/String/prototype/toWellFormed/to-string': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=11660
# https://github.com/tc39/proposal-intl-duration-format/issues/114
'intl402/DurationFormat/prototype/format/style-options-en': [FAIL],

View File

@ -56,6 +56,8 @@ FEATURE_FLAGS = {
'array-grouping': '--harmony-array-grouping',
'change-array-by-copy': '--harmony-change-array-by-copy',
'symbols-as-weakmap-keys': '--harmony-symbol-as-weakmap-key',
'String.prototype.isWellFormed': '--harmony-string-is-well-formed',
'String.prototype.toWellFormed': '--harmony-string-is-well-formed',
}
SKIPPED_FEATURES = set([])

View File

@ -577,30 +577,30 @@ KNOWN_OBJECTS = {
("old_space", 0x04581): "StringSplitCache",
("old_space", 0x04989): "RegExpMultipleCache",
("old_space", 0x04d91): "BuiltinsConstantsTable",
("old_space", 0x05359): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x0537d): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x053a1): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x053c5): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x053e9): "AsyncGeneratorYieldWithAwaitResolveSharedFun",
("old_space", 0x0540d): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x05431): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x05455): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05479): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x0549d): "PromiseAllResolveElementSharedFun",
("old_space", 0x054c1): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x054e5): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05509): "PromiseAnyRejectElementSharedFun",
("old_space", 0x0552d): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x05551): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x05575): "PromiseCatchFinallySharedFun",
("old_space", 0x05599): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x055bd): "PromiseThenFinallySharedFun",
("old_space", 0x055e1): "PromiseThrowerFinallySharedFun",
("old_space", 0x05605): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05629): "ProxyRevokeSharedFun",
("old_space", 0x0564d): "ShadowRealmImportValueFulfilledSFI",
("old_space", 0x05671): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
("old_space", 0x05695): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
("old_space", 0x05361): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x05385): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x053a9): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x053cd): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x053f1): "AsyncGeneratorYieldWithAwaitResolveSharedFun",
("old_space", 0x05415): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x05439): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0545d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05481): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x054a5): "PromiseAllResolveElementSharedFun",
("old_space", 0x054c9): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x054ed): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05511): "PromiseAnyRejectElementSharedFun",
("old_space", 0x05535): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x05559): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0557d): "PromiseCatchFinallySharedFun",
("old_space", 0x055a1): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x055c5): "PromiseThenFinallySharedFun",
("old_space", 0x055e9): "PromiseThrowerFinallySharedFun",
("old_space", 0x0560d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05631): "ProxyRevokeSharedFun",
("old_space", 0x05655): "ShadowRealmImportValueFulfilledSFI",
("old_space", 0x05679): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
("old_space", 0x0569d): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
}
# Lower 32 bits of first page addresses for various heap spaces.