[change-array-by-copy] Implement toReversed
Bug: v8:12764 Change-Id: I7e76647be838749b723400914b144b9ec2a27cd7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3656520 Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/main@{#80703}
This commit is contained in:
parent
bb18bc24b0
commit
116e6a528d
@ -781,6 +781,7 @@ filegroup(
|
||||
"src/builtins/array-slice.tq",
|
||||
"src/builtins/array-some.tq",
|
||||
"src/builtins/array-splice.tq",
|
||||
"src/builtins/array-to-reversed.tq",
|
||||
"src/builtins/array-unshift.tq",
|
||||
"src/builtins/array.tq",
|
||||
"src/builtins/arraybuffer.tq",
|
||||
@ -880,6 +881,7 @@ filegroup(
|
||||
"src/builtins/typed-array-some.tq",
|
||||
"src/builtins/typed-array-sort.tq",
|
||||
"src/builtins/typed-array-subarray.tq",
|
||||
"src/builtins/typed-array-to-reversed.tq",
|
||||
"src/builtins/typed-array-values.tq",
|
||||
"src/builtins/typed-array.tq",
|
||||
"src/builtins/weak-ref.tq",
|
||||
|
2
BUILD.gn
2
BUILD.gn
@ -1683,6 +1683,7 @@ torque_files = [
|
||||
"src/builtins/array-slice.tq",
|
||||
"src/builtins/array-some.tq",
|
||||
"src/builtins/array-splice.tq",
|
||||
"src/builtins/array-to-reversed.tq",
|
||||
"src/builtins/array-unshift.tq",
|
||||
"src/builtins/array.tq",
|
||||
"src/builtins/arraybuffer.tq",
|
||||
@ -1782,6 +1783,7 @@ torque_files = [
|
||||
"src/builtins/typed-array-some.tq",
|
||||
"src/builtins/typed-array-sort.tq",
|
||||
"src/builtins/typed-array-subarray.tq",
|
||||
"src/builtins/typed-array-to-reversed.tq",
|
||||
"src/builtins/typed-array-values.tq",
|
||||
"src/builtins/typed-array.tq",
|
||||
"src/builtins/weak-ref.tq",
|
||||
|
102
src/builtins/array-to-reversed.tq
Normal file
102
src/builtins/array-to-reversed.tq
Normal file
@ -0,0 +1,102 @@
|
||||
// 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 {
|
||||
macro FastPackedArrayToReversed<Accessor: type, T: type>(
|
||||
implicit context: Context)(
|
||||
kind: constexpr ElementsKind, elements: FixedArrayBase,
|
||||
length: Smi): JSArray {
|
||||
// 3. Let A be ? ArrayCreate(𝔽(len)).
|
||||
const copy: FixedArrayBase =
|
||||
AllocateFixedArray(kind, SmiUntag(length), AllocationFlag::kNone);
|
||||
|
||||
// 4. Let k be 0.
|
||||
let k: Smi = 0;
|
||||
|
||||
// 5. Repeat, while k < len,
|
||||
while (k < length) {
|
||||
// a. Let from be ! ToString(𝔽(len - k - 1)).
|
||||
// b. Let Pk be ! ToString(𝔽(k)).
|
||||
const from = length - k - 1;
|
||||
|
||||
// c. Let fromValue be ? Get(O, from).
|
||||
const fromValue: T = LoadElement<Accessor, T>(elements, from);
|
||||
|
||||
// d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue).
|
||||
StoreElement<Accessor>(copy, k, fromValue);
|
||||
|
||||
// e. Set k to k + 1.
|
||||
++k;
|
||||
}
|
||||
|
||||
// 6. Return A.
|
||||
const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context));
|
||||
return NewJSArray(map, copy);
|
||||
}
|
||||
|
||||
macro TryFastPackedArrayToReversed(implicit context: Context)(receiver: JSAny):
|
||||
JSArray labels Slow {
|
||||
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||
|
||||
const kind: ElementsKind = array.map.elements_kind;
|
||||
if (kind == ElementsKind::PACKED_SMI_ELEMENTS) {
|
||||
return FastPackedArrayToReversed<array::FastPackedSmiElements, Smi>(
|
||||
ElementsKind::PACKED_SMI_ELEMENTS, array.elements, array.length);
|
||||
}
|
||||
if (kind == ElementsKind::PACKED_ELEMENTS) {
|
||||
return FastPackedArrayToReversed<array::FastPackedObjectElements, JSAny>(
|
||||
ElementsKind::PACKED_ELEMENTS, array.elements, array.length);
|
||||
}
|
||||
if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
|
||||
return FastPackedArrayToReversed<array::FastPackedDoubleElements, float64>(
|
||||
ElementsKind::PACKED_DOUBLE_ELEMENTS, array.elements, array.length);
|
||||
}
|
||||
|
||||
goto Slow;
|
||||
}
|
||||
|
||||
transitioning macro GenericArrayToReversed(
|
||||
context: Context, receiver: JSAny): JSAny {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
const object: JSReceiver = ToObject_Inline(context, receiver);
|
||||
|
||||
// 2. Let len be ? LengthOfArrayLike(O).
|
||||
const len: Number = GetLengthProperty(object);
|
||||
|
||||
// 3. Let A be ? ArrayCreate(𝔽(len)).
|
||||
const copy = ArrayCreate(len);
|
||||
|
||||
// 4. Let k be 0.
|
||||
let k: Number = 0;
|
||||
|
||||
// 5. Repeat, while k < len,
|
||||
while (k < len) {
|
||||
// a. Let from be ! ToString(𝔽(len - k - 1)).
|
||||
// b. Let Pk be ! ToString(𝔽(k)).
|
||||
const from: Number = len - k - 1;
|
||||
|
||||
// c. Let fromValue be ? Get(object, from).
|
||||
const fromValue = GetProperty(object, from);
|
||||
|
||||
// d. Perform ! CreateDataPropertyOrThrow(A, Pk, fromValue).
|
||||
FastCreateDataProperty(copy, k, fromValue);
|
||||
|
||||
// e. Set k to k + 1.
|
||||
++k;
|
||||
}
|
||||
|
||||
// 6. Return A.
|
||||
return copy;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-change-array-by-copy/#sec-array.prototype.toReversed
|
||||
transitioning javascript builtin ArrayPrototypeToReversed(
|
||||
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
|
||||
try {
|
||||
return TryFastPackedArrayToReversed(receiver) otherwise Slow;
|
||||
} label Slow {
|
||||
return GenericArrayToReversed(context, receiver);
|
||||
}
|
||||
}
|
||||
}
|
@ -475,4 +475,15 @@ transitioning macro TypedArraySpeciesCreateByBuffer(implicit context: Context)(
|
||||
Convert<Number>(newLength));
|
||||
return typedArray;
|
||||
}
|
||||
|
||||
transitioning macro TypedArrayCreateSameType(implicit context: Context)(
|
||||
exemplar: JSTypedArray, newLength: uintptr): JSTypedArray {
|
||||
const constructor = GetDefaultConstructor(exemplar);
|
||||
const typedArray = CreateTypedArray(
|
||||
context, constructor, constructor, Convert<Number>(newLength), Undefined,
|
||||
Undefined);
|
||||
dcheck(!IsDetachedBuffer(typedArray.buffer));
|
||||
dcheck(exemplar.elements_kind == typedArray.elements_kind);
|
||||
return typedArray;
|
||||
}
|
||||
}
|
||||
|
43
src/builtins/typed-array-to-reversed.tq
Normal file
43
src/builtins/typed-array-to-reversed.tq
Normal file
@ -0,0 +1,43 @@
|
||||
// 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 typed_array {
|
||||
// https://tc39.es/proposal-change-array-by-copy/#sec-%typedarray%.prototype.toReversed
|
||||
transitioning javascript builtin TypedArrayPrototypeToReversed(
|
||||
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
|
||||
// 1. Let O be the this value.
|
||||
// 2. Perform ? ValidateTypedArray(O).
|
||||
// 3. Let length be O.[[ArrayLength]].
|
||||
const len = ValidateTypedArrayAndGetLength(
|
||||
context, receiver, '%TypedArray%.prototype.toReversed');
|
||||
const src: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
|
||||
|
||||
// 4. Let A be ? TypedArrayCreateSameType(O, « 𝔽(length) »).
|
||||
const copy = TypedArrayCreateSameType(src, len);
|
||||
const accessor: TypedArrayAccessor =
|
||||
GetTypedArrayAccessor(copy.elements_kind);
|
||||
|
||||
// 5. Let k be 0.
|
||||
let k: uintptr = 0;
|
||||
|
||||
// 6. Repeat, while k < length,
|
||||
while (k < len) {
|
||||
// a. Let from be ! ToString(𝔽(length - k - 1)).
|
||||
// b. Let Pk be ! ToString(𝔽(k)).
|
||||
const from = len - k - 1;
|
||||
|
||||
// c. Let fromValue be ! Get(O, from).
|
||||
const fromValue = accessor.LoadNumeric(src, from);
|
||||
|
||||
// d. Perform ! Set(A, Pk, kValue, true).
|
||||
accessor.StoreNumeric(context, copy, k, fromValue);
|
||||
|
||||
// e. Set k to k + 1.
|
||||
++k;
|
||||
}
|
||||
|
||||
// 7. Return A.
|
||||
return copy;
|
||||
}
|
||||
}
|
@ -307,7 +307,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
||||
V(harmony_import_assertions, "harmony import assertions") \
|
||||
V(harmony_temporal, "Temporal") \
|
||||
V(harmony_shadow_realm, "harmony ShadowRealm") \
|
||||
V(harmony_struct, "harmony structs and shared structs")
|
||||
V(harmony_struct, "harmony structs and shared structs") \
|
||||
V(harmony_change_array_by_copy, "harmony change-Array-by-copy")
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
|
@ -4486,6 +4486,34 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_best_fit_matcher)
|
||||
|
||||
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_change_array_by_copy() {
|
||||
if (!FLAG_harmony_change_array_by_copy) return;
|
||||
|
||||
{
|
||||
Handle<JSFunction> array_function(native_context()->array_function(),
|
||||
isolate());
|
||||
Handle<JSObject> array_prototype(
|
||||
JSObject::cast(array_function->instance_prototype()), isolate());
|
||||
|
||||
SimpleInstallFunction(isolate_, array_prototype, "toReversed",
|
||||
Builtin::kArrayPrototypeToReversed, 0, true);
|
||||
|
||||
Handle<JSObject> unscopables = Handle<JSObject>::cast(
|
||||
JSObject::GetProperty(isolate(), array_prototype,
|
||||
isolate()->factory()->unscopables_symbol())
|
||||
.ToHandleChecked());
|
||||
|
||||
InstallTrueValuedProperty(isolate_, unscopables, "toReversed");
|
||||
}
|
||||
|
||||
{
|
||||
Handle<JSObject> prototype(native_context()->typed_array_prototype(),
|
||||
isolate());
|
||||
SimpleInstallFunction(isolate_, prototype, "toReversed",
|
||||
Builtin::kTypedArrayPrototypeToReversed, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_shadow_realm() {
|
||||
if (!FLAG_harmony_shadow_realm) return;
|
||||
Factory* factory = isolate()->factory();
|
||||
|
107
test/mjsunit/harmony/array-to-reversed.js
Normal file
107
test/mjsunit/harmony/array-to-reversed.js
Normal file
@ -0,0 +1,107 @@
|
||||
// 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(0, Array.prototype.toReversed.length);
|
||||
assertEquals("toReversed", Array.prototype.toReversed.name);
|
||||
|
||||
(function TestSmiPacked() {
|
||||
let a = [1,2,3,4];
|
||||
let r = a.toReversed();
|
||||
assertEquals([1,2,3,4], a);
|
||||
assertEquals([4,3,2,1], r);
|
||||
assertFalse(a === r);
|
||||
})();
|
||||
|
||||
(function TestDoublePacked() {
|
||||
let a = [1.1,2.2,3.3,4.4];
|
||||
let r = a.toReversed();
|
||||
assertEquals([1.1,2.2,3.3,4.4], a);
|
||||
assertEquals([4.4,3.3,2.2,1.1], r);
|
||||
assertFalse(a === r);
|
||||
})();
|
||||
|
||||
(function TestPacked() {
|
||||
let a = [true,false,1,42.42];
|
||||
let r = a.toReversed();
|
||||
assertEquals([true,false,1,42.42], a);
|
||||
assertEquals([42.42,1,false,true], r);
|
||||
assertFalse(a === r);
|
||||
})();
|
||||
|
||||
(function TestGeneric() {
|
||||
let a = { length: 4,
|
||||
get "0"() { return "hello"; },
|
||||
get "1"() { return "cursed"; },
|
||||
get "2"() { return "java"; },
|
||||
get "3"() { return "script" } };
|
||||
let r = Array.prototype.toReversed.call(a);
|
||||
assertEquals("hello", a[0]);
|
||||
assertEquals(["script","java","cursed","hello"], r);
|
||||
assertFalse(a === r);
|
||||
assertTrue(Array.isArray(r));
|
||||
assertEquals(Array, r.constructor);
|
||||
})();
|
||||
|
||||
(function TestReadOrder() {
|
||||
let order = [];
|
||||
let a = { length: 4,
|
||||
get "0"() { order.push("4th"); return "4th"; },
|
||||
get "1"() { order.push("3rd"); return "3rd"; },
|
||||
get "2"() { order.push("2nd"); return "2nd"; },
|
||||
get "3"() { order.push("1st"); return "1st"; } };
|
||||
let r = Array.prototype.toReversed.call(a);
|
||||
assertEquals(["1st","2nd","3rd","4th"], r);
|
||||
assertEquals(["1st","2nd","3rd","4th"], order);
|
||||
})();
|
||||
|
||||
(function TestTooBig() {
|
||||
let a = { length: Math.pow(2, 32) };
|
||||
assertThrows(() => Array.prototype.toReversed.call(a), RangeError);
|
||||
})();
|
||||
|
||||
(function TestNoSpecies() {
|
||||
class MyArray extends Array {
|
||||
static get [Symbol.species]() { return MyArray; }
|
||||
}
|
||||
assertEquals(Array, (new MyArray()).toReversed().constructor);
|
||||
})();
|
||||
|
||||
// All tests after this have an invalidated elements-on-prototype protector.
|
||||
(function TestNoHoles() {
|
||||
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'));
|
||||
})();
|
||||
|
||||
(function TestMidIterationShenanigans() {
|
||||
let 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.
|
||||
let r = a.toReversed();
|
||||
assertEquals(1, a.length);
|
||||
assertEquals([4,3,2,1], r);
|
||||
|
||||
// Values can be changed mid-iteration.
|
||||
a = { length: 4,
|
||||
"0": 1,
|
||||
get "1"() { a[0] = "poof"; return 2; },
|
||||
"2": 3,
|
||||
"3": 4,
|
||||
__proto__: Array.prototype };
|
||||
r = a.toReversed();
|
||||
assertEquals([4,3,2,"poof"], r);
|
||||
})();
|
35
test/mjsunit/harmony/typedarray-to-reversed.js
Normal file
35
test/mjsunit/harmony/typedarray-to-reversed.js
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2018 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
|
||||
|
||||
d8.file.execute('test/mjsunit/typedarray-helpers.js');
|
||||
|
||||
(function TestSurface() {
|
||||
for (let TA of ctors) {
|
||||
assertEquals(TA.prototype.toReversed.length, 0);
|
||||
assertEquals(TA.prototype.toReversed.name, "toReversed");
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestBasic() {
|
||||
for (let TA of ctors) {
|
||||
let a = new TA(4);
|
||||
for (let i = 0; i < 4; i++) {
|
||||
a[i] = i + "";
|
||||
}
|
||||
let r = a.toReversed();
|
||||
for (let i = 0; i < 4; i++) {
|
||||
assertEquals(a[i], r[4-i-1]);
|
||||
}
|
||||
assertFalse(a === r);
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestNoSpecies() {
|
||||
class MyUint8Array extends Uint8Array {
|
||||
static get [Symbol.species]() { return MyUint8Array; }
|
||||
}
|
||||
assertEquals(Uint8Array, (new MyUint8Array()).toReversed().constructor);
|
||||
})();
|
@ -536,30 +536,30 @@ KNOWN_OBJECTS = {
|
||||
("old_space", 0x04b35): "StringSplitCache",
|
||||
("old_space", 0x04f3d): "RegExpMultipleCache",
|
||||
("old_space", 0x05345): "BuiltinsConstantsTable",
|
||||
("old_space", 0x05779): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x0579d): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x057c1): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x057e5): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x05809): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x0582d): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05851): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x05875): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x05899): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x058bd): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x058e1): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x05905): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x05929): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x0594d): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05971): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x05995): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x059b9): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x059dd): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x05a01): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x05a25): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x05a49): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x05a6d): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x05a91): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x05ab5): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
("old_space", 0x0577d): "AsyncFunctionAwaitRejectSharedFun",
|
||||
("old_space", 0x057a1): "AsyncFunctionAwaitResolveSharedFun",
|
||||
("old_space", 0x057c5): "AsyncGeneratorAwaitRejectSharedFun",
|
||||
("old_space", 0x057e9): "AsyncGeneratorAwaitResolveSharedFun",
|
||||
("old_space", 0x0580d): "AsyncGeneratorYieldResolveSharedFun",
|
||||
("old_space", 0x05831): "AsyncGeneratorReturnResolveSharedFun",
|
||||
("old_space", 0x05855): "AsyncGeneratorReturnClosedRejectSharedFun",
|
||||
("old_space", 0x05879): "AsyncGeneratorReturnClosedResolveSharedFun",
|
||||
("old_space", 0x0589d): "AsyncIteratorValueUnwrapSharedFun",
|
||||
("old_space", 0x058c1): "PromiseAllResolveElementSharedFun",
|
||||
("old_space", 0x058e5): "PromiseAllSettledResolveElementSharedFun",
|
||||
("old_space", 0x05909): "PromiseAllSettledRejectElementSharedFun",
|
||||
("old_space", 0x0592d): "PromiseAnyRejectElementSharedFun",
|
||||
("old_space", 0x05951): "PromiseCapabilityDefaultRejectSharedFun",
|
||||
("old_space", 0x05975): "PromiseCapabilityDefaultResolveSharedFun",
|
||||
("old_space", 0x05999): "PromiseCatchFinallySharedFun",
|
||||
("old_space", 0x059bd): "PromiseGetCapabilitiesExecutorSharedFun",
|
||||
("old_space", 0x059e1): "PromiseThenFinallySharedFun",
|
||||
("old_space", 0x05a05): "PromiseThrowerFinallySharedFun",
|
||||
("old_space", 0x05a29): "PromiseValueThunkFinallySharedFun",
|
||||
("old_space", 0x05a4d): "ProxyRevokeSharedFun",
|
||||
("old_space", 0x05a71): "ShadowRealmImportValueFulfilledSFI",
|
||||
("old_space", 0x05a95): "SourceTextModuleExecuteAsyncModuleFulfilledSFI",
|
||||
("old_space", 0x05ab9): "SourceTextModuleExecuteAsyncModuleRejectedSFI",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user