[change-array-by-copy] Implement Array.prototype.toSpliced

Drive-by: add unscopable test for Array.prototype.toReversed.

Bug: v8:12764
Change-Id: I9d7dd8d4eae6d23811382b6795c2c6ff7f76be72
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3717552
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81364}
This commit is contained in:
Shu-yu Guo 2022-06-24 14:19:38 -07:00 committed by V8 LUCI CQ
parent 902b23272a
commit 3c4c25dbd4
9 changed files with 468 additions and 65 deletions

View File

@ -785,6 +785,7 @@ filegroup(
"src/builtins/array-some.tq",
"src/builtins/array-splice.tq",
"src/builtins/array-to-reversed.tq",
"src/builtins/array-to-spliced.tq",
"src/builtins/array-unshift.tq",
"src/builtins/array-with.tq",
"src/builtins/array.tq",

View File

@ -1686,6 +1686,7 @@ torque_files = [
"src/builtins/array-some.tq",
"src/builtins/array-splice.tq",
"src/builtins/array-to-reversed.tq",
"src/builtins/array-to-spliced.tq",
"src/builtins/array-unshift.tq",
"src/builtins/array-with.tq",
"src/builtins/array.tq",

View File

@ -58,6 +58,26 @@ macro DoCopyElements<FixedArrayType : type extends FixedArrayBase>(
Convert<intptr>(srcIndex), Convert<intptr>(count));
}
macro InsertArgumentsIntoFastPackedArray<
FixedArrayType : type extends FixedArrayBase, ElementType: type>(
dst: JSArray, dstStart: Smi, args: Arguments,
argsStart: constexpr IntegerLiteral, insertCount: Smi): void {
// Copy arguments.
let k: Smi = dstStart;
if (insertCount > 0) {
dcheck(Convert<intptr>(insertCount) == args.length - argsStart);
const typedNewElements: FixedArrayType =
UnsafeCast<FixedArrayType>(dst.elements);
for (let i: intptr = ConstexprIntegerLiteralToIntptr(argsStart);
i < args.length; ++i) {
const e: JSAny = args[i];
// The argument elements were already validated to be an appropriate
// {ElementType} to store in {FixedArrayType}.
typedNewElements[k++] = UnsafeCast<ElementType>(e);
}
}
}
macro
FastSplice<FixedArrayType : type extends FixedArrayBase, ElementType: type>(
implicit context: Context)(
@ -97,22 +117,47 @@ FastSplice<FixedArrayType : type extends FixedArrayBase, ElementType: type>(
}
// Copy arguments.
let k: Smi = actualStart;
if (insertCount > 0) {
const typedNewElements: FixedArrayType =
UnsafeCast<FixedArrayType>(a.elements);
for (let i: intptr = 2; i < args.length; ++i) {
const e: JSAny = args[i];
// The argument elements were already validated to be an appropriate
// {ElementType} to store in {FixedArrayType}.
typedNewElements[k++] = UnsafeCast<ElementType>(e);
}
}
InsertArgumentsIntoFastPackedArray<FixedArrayType, ElementType>(
a, actualStart, args, 2, insertCount);
// Update the array's length after all the FixedArray shuffling is done.
a.length = newLength;
}
transitioning macro TransitionElementsKindForInsertionIfNeeded(
context: Context, a: JSArray, originalElementsKind: ElementsKind,
args: Arguments, argsStart: constexpr IntegerLiteral): ElementsKind {
dcheck(a.map.elements_kind == originalElementsKind);
let elementsKind = originalElementsKind;
for (let k: intptr = ConstexprIntegerLiteralToIntptr(argsStart);
k < args.length; ++k) {
const e = args[k];
if (IsFastSmiElementsKind(elementsKind)) {
if (TaggedIsNotSmi(e)) {
const heapObject: HeapObject = UnsafeCast<HeapObject>(e);
elementsKind = IsHeapNumber(heapObject) ?
AllowDoubleElements(elementsKind) :
AllowNonNumberElements(elementsKind);
}
} else if (IsDoubleElementsKind(elementsKind)) {
if (!IsNumber(e)) {
elementsKind = AllowNonNumberElements(elementsKind);
}
} else {
// Already generic.
break;
}
}
if (elementsKind != originalElementsKind) {
const smiElementsKind: Smi = Convert<Smi>(Convert<int32>(elementsKind));
TransitionElementsKindWithKind(context, a, smiElementsKind);
}
return elementsKind;
}
transitioning macro FastArraySplice(
context: Context, args: Arguments, o: JSReceiver,
originalLengthNumber: Number, actualStartNumber: Number, insertCount: Smi,
@ -136,27 +181,8 @@ transitioning macro FastArraySplice(
let elementsKind: ElementsKind = EnsureArrayPushable(map) otherwise Bailout;
if (!IsFastElementsKind(elementsKind)) goto Bailout;
const oldElementsKind: ElementsKind = elementsKind;
for (let i: intptr = 2; i < args.length; ++i) {
const e: JSAny = args[i];
if (IsFastSmiElementsKind(elementsKind)) {
if (TaggedIsNotSmi(e)) {
const heapObject: HeapObject = UnsafeCast<HeapObject>(e);
elementsKind = IsHeapNumber(heapObject) ?
AllowDoubleElements(elementsKind) :
AllowNonNumberElements(elementsKind);
}
} else if (IsDoubleElementsKind(elementsKind)) {
if (!IsNumber(e)) {
elementsKind = AllowNonNumberElements(elementsKind);
}
}
}
if (elementsKind != oldElementsKind) {
const smiElementsKind: Smi = Convert<Smi>(Convert<int32>(elementsKind));
TransitionElementsKindWithKind(context, a, smiElementsKind);
}
elementsKind = TransitionElementsKindForInsertionIfNeeded(
context, a, elementsKind, args, 2);
// Make sure that the length hasn't been changed by side-effect.
const length: Smi = Cast<Smi>(a.length) otherwise Bailout;
@ -403,7 +429,7 @@ ArrayPrototypeSplice(
// Bailout exception.
const newLength: Number = len + insertCount - actualDeleteCount;
if (newLength > kMaxSafeInteger) {
ThrowTypeError(MessageTemplate::kInvalidArrayLength, start);
ThrowTypeError(MessageTemplate::kInvalidArrayLength, newLength);
}
try {

View File

@ -56,8 +56,8 @@ macro TryFastPackedArrayToReversed(implicit context: Context)(receiver: JSAny):
goto Slow;
}
transitioning macro GenericArrayToReversed(
context: Context, receiver: JSAny): JSAny {
transitioning macro GenericArrayToReversed(implicit context: Context)(
receiver: JSAny): JSAny {
// 1. Let O be ? ToObject(this value).
const object: JSReceiver = ToObject_Inline(context, receiver);
@ -96,7 +96,7 @@ transitioning javascript builtin ArrayPrototypeToReversed(
try {
return TryFastPackedArrayToReversed(receiver) otherwise Slow;
} label Slow {
return GenericArrayToReversed(context, receiver);
return GenericArrayToReversed(receiver);
}
}
}

View File

@ -0,0 +1,227 @@
// 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.
namespace array {
// Makes a copy of the source array for toSpliced without inserting the new
// items.
macro CopyFastPackedArrayForToSpliced(implicit context: Context)(
kind: constexpr ElementsKind, array: JSArray, newLenSmi: Smi,
actualStartSmi: Smi, insertCountSmi: Smi,
actualDeleteCountSmi: Smi): JSArray {
const newLen: intptr = Convert<intptr>(newLenSmi);
const actualStart: intptr = Convert<intptr>(actualStartSmi);
const insertCount: intptr = Convert<intptr>(insertCountSmi);
const actualDeleteCount: intptr = Convert<intptr>(actualDeleteCountSmi);
const copy: FixedArrayBase =
AllocateFixedArray(kind, newLen, AllocationFlag::kNone);
// Copy the part before the inserted items.
CopyElements(kind, copy, 0, array.elements, 0, actualStart);
// Leave the items to be inserted for later since it could transition the
// ElementsKind.
// Copy the part after the inserted items.
const secondPartStart: intptr = actualStart + insertCount;
const secondPartLen: intptr = newLen - secondPartStart;
const r: intptr = actualStart + actualDeleteCount;
dcheck(Convert<Smi>(r + secondPartLen) <= array.length);
CopyElements(kind, copy, secondPartStart, array.elements, r, secondPartLen);
const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context));
return NewJSArray(map, copy);
}
transitioning macro TryFastArrayToSpliced(implicit context: Context)(
args: Arguments, o: JSReceiver, originalLenNumber: Number,
newLenNumber: Number, actualStartNumber: Number, insertCount: Smi,
actualDeleteCountNumber: Number): JSArray labels Slow {
const newLen: Smi = Cast<Smi>(newLenNumber) otherwise Slow;
const actualStart: Smi = Cast<Smi>(actualStartNumber) otherwise Slow;
const actualDeleteCount: Smi =
Cast<Smi>(actualDeleteCountNumber) otherwise Slow;
const array: FastJSArray = Cast<FastJSArray>(o) otherwise Slow;
// If any argument coercion shrunk the source array, go to the slow case.
const originalLen: Smi = Cast<Smi>(originalLenNumber) otherwise Slow;
if (originalLen > array.length) goto Slow;
// Array#toSpliced does not preserve holes and always creates packed Arrays.
// Holes in the source array-like are treated like any other element and the
// value is computed with Get. So, there are only fast paths for packed
// elements.
let elementsKind: ElementsKind = array.map.elements_kind;
if (!IsFastPackedElementsKind(elementsKind)) goto Slow;
// Make a copy before inserting the new items, as doing so can transition the
// ElementsKind.
let copy: JSArray;
if (elementsKind == ElementsKind::PACKED_SMI_ELEMENTS) {
copy = CopyFastPackedArrayForToSpliced(
ElementsKind::PACKED_SMI_ELEMENTS, array, newLen, actualStart,
insertCount, actualDeleteCount);
} else if (elementsKind == ElementsKind::PACKED_ELEMENTS) {
copy = CopyFastPackedArrayForToSpliced(
ElementsKind::PACKED_ELEMENTS, array, newLen, actualStart, insertCount,
actualDeleteCount);
} else {
dcheck(elementsKind == ElementsKind::PACKED_DOUBLE_ELEMENTS);
copy = CopyFastPackedArrayForToSpliced(
ElementsKind::PACKED_DOUBLE_ELEMENTS, array, newLen, actualStart,
insertCount, actualDeleteCount);
}
// Array#toSpliced's parameters are (start, deleteCount, ...items), so the
// first item to insert is at index 2.
const kArgsStart = 2;
elementsKind = TransitionElementsKindForInsertionIfNeeded(
context, copy, elementsKind, args, kArgsStart);
// Insert the items.
dcheck(IsFastPackedElementsKind(elementsKind));
if (IsFastSmiOrTaggedElementsKind(elementsKind)) {
InsertArgumentsIntoFastPackedArray<FixedArray, JSAny>(
copy, actualStart, args, kArgsStart, insertCount);
} else {
InsertArgumentsIntoFastPackedArray<FixedDoubleArray, Number>(
copy, actualStart, args, kArgsStart, insertCount);
}
return copy;
}
transitioning macro GenericArrayToSpliced(implicit context: Context)(
args: Arguments, o: JSReceiver, newLen: Number, actualStart: Number,
actualDeleteCount: Number): JSArray {
// 13. Let A be ? ArrayCreate(𝔽(newLen)).
const copy = ArrayCreate(newLen);
// 14. Let i be 0.
let i: Number = 0;
// 15. Let r be actualStart + actualDeleteCount.
let r: Number = actualStart + actualDeleteCount;
// 16. Repeat, while i < actualStart,
while (i < actualStart) {
// a. Let Pi be ! ToString(𝔽(i)).
// b. Let iValue be ? Get(O, Pi).
const iValue = GetProperty(o, i);
// c. Perform ! CreateDataPropertyOrThrow(A, Pi, iValue).
FastCreateDataProperty(copy, i, iValue);
// d. Set i to i + 1.
++i;
}
if (args.length > 2) {
// 17. For each element E of items, do
for (let k: intptr = 2; k < args.length; ++k) {
const e = args[k];
// a. Let Pi be ! ToString(𝔽(i)).
// b. Perform ! CreateDataPropertyOrThrow(A, Pi, E).
FastCreateDataProperty(copy, i, e);
// c. Set i to i + 1.
++i;
}
}
// 18. Repeat, while i < newLen,
while (i < newLen) {
// a. Let Pi be ! ToString(𝔽(i)).
// b. Let from be ! ToString(𝔽(r)).
// c. Let fromValue be ? Get(O, from).
const fromValue = GetProperty(o, r);
// d. Perform ! CreateDataPropertyOrThrow(A, Pi, fromValue).
FastCreateDataProperty(copy, i, fromValue);
// e. Set i to i + 1.
++i;
// f. Set r to r + 1.
++r;
}
// 19. Return A.
return copy;
}
// https://tc39.es/proposal-change-array-by-copy/#sec-array.prototype.toSpliced
transitioning javascript builtin ArrayPrototypeToSpliced(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
const start = arguments[0];
const deleteCount = arguments[1];
// 1. Let O be ? ToObject(this value).
const o: JSReceiver = ToObject(context, receiver);
// 2. Let len be ? LengthOfArrayLike(O).
const len: Number = GetLengthProperty(o);
// 3. Let relativeStart be ? ToIntegerOrInfinity(start).
const relativeStart: Number = ToInteger_Inline(start);
// 4. If relativeStart is -∞, let actualStart be 0.
// 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart,
// 0).
// 6. Else, let actualStart be min(relativeStart, len).
//
// TODO(syg): Support Number length values in ConvertAndClampRelativeIndex.
const actualStart = relativeStart < 0 ? Max((len + relativeStart), 0) :
Min(relativeStart, len);
let insertCount: Smi;
let actualDeleteCount: Number;
if (arguments.length == 0) {
// 7. Let insertCount be the number of elements in items.
insertCount = 0;
// 8. If start is not present, then
// a. Let actualDeleteCount be 0.
actualDeleteCount = 0;
} else if (arguments.length == 1) {
// 7. Let insertCount be the number of elements in items.
insertCount = 0;
// 9. Else if deleteCount is not present, then
// a. Let actualDeleteCount be len - actualStart.
actualDeleteCount = len - actualStart;
} else {
// 7. Let insertCount be the number of elements in items.
insertCount = Convert<Smi>(arguments.length) - 2;
// 10. Else,
// a. Let dc be ? ToIntegerOrInfinity(deleteCount).
// b. Let actualDeleteCount be the result of clamping dc between 0 and len
// - actualStart.
const dc = ToInteger_Inline(deleteCount);
actualDeleteCount = Min(Max(0, dc), len - actualStart);
}
// 11. Let newLen be len + insertCount - actualDeleteCount.
const newLen = len + insertCount - actualDeleteCount;
// 12. If newLen > 2^53 - 1, throw a TypeError exception.
if (newLen > kMaxSafeInteger) {
ThrowTypeError(MessageTemplate::kInvalidArrayLength, newLen);
}
if (newLen == 0) return ArrayCreate(0);
try {
return TryFastArrayToSpliced(
arguments, o, len, newLen, actualStart, insertCount, actualDeleteCount)
otherwise Slow;
} label Slow {
return GenericArrayToSpliced(
arguments, o, newLen, actualStart, actualDeleteCount);
}
}
}

View File

@ -4524,6 +4524,8 @@ void Genesis::InitializeGlobal_harmony_change_array_by_copy() {
SimpleInstallFunction(isolate_, array_prototype, "toReversed",
Builtin::kArrayPrototypeToReversed, 0, true);
SimpleInstallFunction(isolate_, array_prototype, "toSpliced",
Builtin::kArrayPrototypeToSpliced, 2, false);
SimpleInstallFunction(isolate_, array_prototype, "with",
Builtin::kArrayPrototypeWith, 2, true);
@ -4533,6 +4535,7 @@ void Genesis::InitializeGlobal_harmony_change_array_by_copy() {
.ToHandleChecked());
InstallTrueValuedProperty(isolate_, unscopables, "toReversed");
InstallTrueValuedProperty(isolate_, unscopables, "toSpliced");
}
{

View File

@ -74,12 +74,11 @@ assertEquals("toReversed", Array.prototype.toReversed.name);
let a = [,,,,];
Array.prototype[3] = "on proto";
let r = a.toReversed();
assertEquals([,,,,], a);
assertEquals(["on proto",undefined,undefined,undefined], r);
assertTrue(r.hasOwnProperty('0'));
assertTrue(r.hasOwnProperty('1'));
assertTrue(r.hasOwnProperty('2'));
assertTrue(r.hasOwnProperty('3'));
for (let i = 0; i < a.length; i++) {
assertFalse(a.hasOwnProperty(i));
assertTrue(r.hasOwnProperty(i));
}
})();
(function TestMidIterationShenanigans() {
@ -105,3 +104,5 @@ assertEquals("toReversed", Array.prototype.toReversed.name);
r = a.toReversed();
assertEquals([4,3,2,"poof"], r);
})();
assertEquals(Array.prototype[Symbol.unscopables].toReversed, true);

View File

@ -0,0 +1,144 @@
// 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: --harmony-change-array-by-copy
assertEquals(2, Array.prototype.toSpliced.length);
assertEquals("toSpliced", Array.prototype.toSpliced.name);
function TerribleCopy(input) {
let copy;
if (Array.isArray(input)) {
copy = [...input];
} else {
copy = { length: input.length };
for (let i = 0; i < input.length; i++) {
copy[i] = input[i];
}
}
return copy;
}
function AssertToSplicedAndSpliceSameResult(input, ...args) {
const orig = TerribleCopy(input);
const s = Array.prototype.toSpliced.apply(input, args);
const copy = TerribleCopy(input);
Array.prototype.splice.apply(copy, args);
// The in-place spliced version should be pairwise equal to the toSpliced,
// modulo being an actual Array if the input is generic.
if (Array.isArray(input)) {
assertEquals(copy, s);
} else {
assertEquals(copy.length, s.length);
for (let i = 0; i < copy.length; i++) {
assertEquals(copy[i], s[i]);
}
}
// The original input should be unchanged.
assertEquals(orig, input);
// The result of toSpliced() is a copy.
assertFalse(s === input);
}
function TestToSplicedBasicBehaviorHelper(input, itemsToInsert) {
const startIndices = [0, 1, -1, -100, Infinity, -Infinity];
const deleteCounts = [0, 1, 2, 3];
AssertToSplicedAndSpliceSameResult(input);
for (let startIndex of startIndices) {
AssertToSplicedAndSpliceSameResult(input, startIndex);
for (let deleteCount of deleteCounts) {
AssertToSplicedAndSpliceSameResult(input, startIndex, deleteCount);
AssertToSplicedAndSpliceSameResult(input, startIndex, deleteCount,
...itemsToInsert);
}
}
}
// Smi packed
TestToSplicedBasicBehaviorHelper([1,2,3,4], [5,6]);
// Double packed
TestToSplicedBasicBehaviorHelper([1.1,2.2,3.3,4.4], [5.5,6.6]);
// Packed
TestToSplicedBasicBehaviorHelper([true,false,1,42.42], [null,"foo"]);
// Generic
TestToSplicedBasicBehaviorHelper({ length: 4,
get "0"() { return "hello"; },
get "1"() { return "cursed"; },
get "2"() { return "java"; },
get "3"() { return "script" } },
["foo","bar"]);
(function TestReadOrder() {
const order = [];
const a = { length: 4,
get "0"() { order.push("1st"); return "1st"; },
get "1"() { order.push("2nd"); return "2nd"; },
get "2"() { order.push("3rd"); return "3rd"; },
get "3"() { order.push("4th"); return "4th"; } };
const s = Array.prototype.toSpliced.call(a);
assertEquals(["1st","2nd","3rd","4th"], s);
assertEquals(["1st","2nd","3rd","4th"], order);
})();
(function TestTooBig() {
const a = { length: Math.pow(2, 32) };
assertThrows(() => Array.prototype.toSpliced.call(a), RangeError);
})();
(function TestNoSpecies() {
class MyArray extends Array {
static get [Symbol.species]() { return MyArray; }
}
assertEquals(Array, (new MyArray()).toSpliced().constructor);
})();
// All tests after this have an invalidated elements-on-prototype protector.
(function TestNoHoles() {
const a = [,,,,];
Array.prototype[3] = "on proto";
const s = a.toSpliced();
assertEquals([undefined,undefined,undefined,"on proto"], s);
for (let i = 0; i < a.length; i++) {
assertFalse(a.hasOwnProperty(i));
assertTrue(s.hasOwnProperty(i));
}
})();
(function TestMidIterationShenanigans() {
{
const a = { length: 4,
"0": 1,
get "1"() { a.length = 1; return 2; },
"2": 3,
"3": 4,
__proto__: Array.prototype };
// The length is cached before iteration, so mid-iteration resizing does not
// affect the copied array length.
const s = a.toSpliced();
assertEquals(1, a.length);
assertEquals([1,2,3,4], s);
}
{
// Values can be changed mid-iteration.
const a = { length: 4,
"0": 1,
get "1"() { a[3] = "poof"; return 2; },
"2": 3,
"3": 4,
__proto__: Array.prototype };
const s = a.toSpliced();
assertEquals([1,2,3,"poof"], s);
}
})();
assertEquals(Array.prototype[Symbol.unscopables].toSpliced, true);

View File

@ -540,30 +540,30 @@ KNOWN_OBJECTS = {
("old_space", 0x04a25): "StringSplitCache",
("old_space", 0x04e2d): "RegExpMultipleCache",
("old_space", 0x05235): "BuiltinsConstantsTable",
("old_space", 0x05671): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x05695): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x056b9): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x056dd): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x05701): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x05725): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x05749): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x0576d): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05791): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x057b5): "PromiseAllResolveElementSharedFun",
("old_space", 0x057d9): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x057fd): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05821): "PromiseAnyRejectElementSharedFun",
("old_space", 0x05845): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x05869): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x0588d): "PromiseCatchFinallySharedFun",
("old_space", 0x058b1): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x058d5): "PromiseThenFinallySharedFun",
("old_space", 0x058f9): "PromiseThrowerFinallySharedFun",
("old_space", 0x0591d): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05941): "ProxyRevokeSharedFun",
("old_space", 0x05965): "ShadowRealmImportValueFulfilledSFI",
("old_space", 0x05989): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
("old_space", 0x059ad): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
("old_space", 0x05675): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x05699): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x056bd): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x056e1): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x05705): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x05729): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x0574d): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x05771): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x05795): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x057b9): "PromiseAllResolveElementSharedFun",
("old_space", 0x057dd): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x05801): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x05825): "PromiseAnyRejectElementSharedFun",
("old_space", 0x05849): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x0586d): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x05891): "PromiseCatchFinallySharedFun",
("old_space", 0x058b5): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x058d9): "PromiseThenFinallySharedFun",
("old_space", 0x058fd): "PromiseThrowerFinallySharedFun",
("old_space", 0x05921): "PromiseValueThunkFinallySharedFun",
("old_space", 0x05945): "ProxyRevokeSharedFun",
("old_space", 0x05969): "ShadowRealmImportValueFulfilledSFI",
("old_space", 0x0598d): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
("old_space", 0x059b1): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
}
# Lower 32 bits of first page addresses for various heap spaces.