Commit 116e6a52 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by V8 LUCI CQ

[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: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80703}
parent bb18bc24
......@@ -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",
......
......@@ -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",
......
// 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;
}
}
// 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();
......
// 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);
})();
// 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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment