[change-array-by-copy] Refactor ConvertToRelativeIndex

This refactors ConvertToRelativeIndex into a clamping version and a
version that takes OOB labels for the upcoming implementation of
Array#with and TypedArray#with.

Also gets rid of the the "to" in the name, because these macros are
actually converting _from_ a relative index to an absolute one, not
the other way around.

Bug: v8:12764
Change-Id: I8bf1c16ce73008164acbd6b849f4259fb9315274
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3669655
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80786}
This commit is contained in:
Shu-yu Guo 2022-05-26 17:10:11 -07:00 committed by V8 LUCI CQ
parent 5299e11bda
commit 978506c3e2
8 changed files with 78 additions and 35 deletions

View File

@ -3,25 +3,39 @@
// found in the LICENSE file.
namespace array {
macro ConvertRelativeIndex(index: Number, length: Number):
Number labels OutOfBoundsLow, OutOfBoundsHigh {
const relativeIndex = index >= 0 ? index : length + index;
if (relativeIndex < 0) goto OutOfBoundsLow;
if (relativeIndex >= length) goto OutOfBoundsHigh;
return relativeIndex;
}
// https://tc39.es/proposal-item-method/#sec-array.prototype.at
transitioning javascript builtin ArrayPrototypeAt(
js-implicit context: NativeContext, receiver: JSAny)(index: JSAny): JSAny {
// 1. Let O be ? ToObject(this value).
const o = ToObject_Inline(context, receiver);
// 2. Let len be ? LengthOfArrayLike(O).
const len = GetLengthProperty(o);
// 3. Let relativeIndex be ? ToInteger(index).
const relativeIndex = ToInteger_Inline(index);
// 4. If relativeIndex ≥ 0, then
// a. Let k be relativeIndex.
// 5. Else,
// a. Let k be len + relativeIndex.
const k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
// 6. If k < 0 or k ≥ len, then return undefined.
if (k < 0 || k >= len) {
try {
// 3. Let relativeIndex be ? ToInteger(index).
const relativeIndex = ToInteger_Inline(index);
// 4. If relativeIndex ≥ 0, then
// a. Let k be relativeIndex.
// 5. Else,
// a. Let k be len + relativeIndex.
const k = ConvertRelativeIndex(relativeIndex, len) otherwise OutOfBounds,
OutOfBounds;
// 7. Return ? Get(O, ! ToString(k)).
return GetProperty(o, k);
} label OutOfBounds {
// 6. If k < 0 or k ≥ len, then return undefined.
return Undefined;
}
// 7. Return ? Get(O, ! ToString(k)).
return GetProperty(o, k);
}
}

View File

@ -3,8 +3,15 @@
// found in the LICENSE file.
namespace array {
macro ConvertToRelativeIndex(index: Number, length: Number): Number {
return index < 0 ? Max(index + length, 0) : Min(index, length);
macro ConvertAndClampRelativeIndex(index: Number, length: Number): Number {
try {
return ConvertRelativeIndex(index, length) otherwise OutOfBoundsLow,
OutOfBoundsHigh;
} label OutOfBoundsLow {
return 0;
} label OutOfBoundsHigh {
return length;
}
}
// https://tc39.github.io/ecma262/#sec-array.prototype.copyWithin
@ -21,14 +28,14 @@ transitioning javascript builtin ArrayPrototypeCopyWithin(
// 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0);
// else let to be min(relativeTarget, len).
let to: Number = ConvertToRelativeIndex(relativeTarget, length);
let to: Number = ConvertAndClampRelativeIndex(relativeTarget, length);
// 5. Let relativeStart be ? ToInteger(start).
const relativeStart: Number = ToInteger_Inline(arguments[1]);
// 6. If relativeStart < 0, let from be max((len + relativeStart), 0);
// else let from be min(relativeStart, len).
let from: Number = ConvertToRelativeIndex(relativeStart, length);
let from: Number = ConvertAndClampRelativeIndex(relativeStart, length);
// 7. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end).
@ -39,7 +46,7 @@ transitioning javascript builtin ArrayPrototypeCopyWithin(
// 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0);
// else let final be min(relativeEnd, len).
const final: Number = ConvertToRelativeIndex(relativeEnd, length);
const final: Number = ConvertAndClampRelativeIndex(relativeEnd, length);
// 9. Let count be min(final-from, len-to).
let count: Number = Min(final - from, length - to);

View File

@ -1643,44 +1643,65 @@ extern macro IsOneByteStringInstanceType(InstanceType): bool;
// After converting an index to an integer, calculate a relative index:
// return index < 0 ? max(length + index, 0) : min(index, length)
@export
transitioning macro ConvertToRelativeIndex(implicit context: Context)(
transitioning macro ConvertAndClampRelativeIndex(implicit context: Context)(
index: JSAny, length: uintptr): uintptr {
const indexNumber: Number = ToInteger_Inline(index);
return ConvertToRelativeIndex(indexNumber, length);
return ConvertAndClampRelativeIndex(indexNumber, length);
}
// Calculate a relative index:
// return index < 0 ? max(length + index, 0) : min(index, length)
@export
macro ConvertToRelativeIndex(indexNumber: Number, length: uintptr): uintptr {
macro ConvertAndClampRelativeIndex(indexNumber: Number, length: uintptr):
uintptr {
try {
return ConvertRelativeIndex(indexNumber, length) otherwise OutOfBoundsLow,
OutOfBoundsHigh;
} label OutOfBoundsLow {
return 0;
} label OutOfBoundsHigh {
return length;
}
}
// Calculate a relative index with explicit out-of-bounds labels.
macro ConvertRelativeIndex(indexNumber: Number, length: uintptr):
uintptr labels OutOfBoundsLow, OutOfBoundsHigh {
typeswitch (indexNumber) {
case (indexSmi: Smi): {
const indexIntPtr: intptr = Convert<intptr>(indexSmi);
// The logic is implemented using unsigned types.
if (indexIntPtr < 0) {
const relativeIndex: uintptr = Unsigned(indexIntPtr) + length;
return relativeIndex < length ? relativeIndex : 0;
if (relativeIndex < length) return relativeIndex;
goto OutOfBoundsLow;
} else {
const relativeIndex: uintptr = Unsigned(indexIntPtr);
return relativeIndex < length ? relativeIndex : length;
if (relativeIndex < length) return relativeIndex;
goto OutOfBoundsHigh;
}
}
case (indexHeapNumber: HeapNumber): {
dcheck(IsNumberNormalized(indexHeapNumber));
const indexDouble: float64 = Convert<float64>(indexHeapNumber);
// NaNs must already be handled by ConvertToRelativeIndex() version
// NaNs must already be handled by ConvertAndClampRelativeIndex() version
// above accepting JSAny indices.
dcheck(!Float64IsNaN(indexDouble));
const lengthDouble: float64 = Convert<float64>(length);
dcheck(lengthDouble <= kMaxSafeInteger);
if (indexDouble < 0) {
const relativeIndex: float64 = lengthDouble + indexDouble;
return relativeIndex > 0 ? ChangeFloat64ToUintPtr(relativeIndex) : 0;
if (relativeIndex > 0) {
return ChangeFloat64ToUintPtr(relativeIndex);
}
goto OutOfBoundsLow;
} else {
return ChangeFloat64ToUintPtr(
indexDouble < lengthDouble ? indexDouble : lengthDouble);
if (indexDouble < lengthDouble) {
return ChangeFloat64ToUintPtr(indexDouble);
}
goto OutOfBoundsHigh;
}
}
}

View File

@ -17,13 +17,13 @@ transitioning javascript builtin StringPrototypeSlice(
// Convert {start} to a relative index.
const arg0 = arguments[0];
const start: uintptr =
arg0 != Undefined ? ConvertToRelativeIndex(arg0, length) : 0;
arg0 != Undefined ? ConvertAndClampRelativeIndex(arg0, length) : 0;
// 5. If end is undefined, let intEnd be len;
// else Convert {end} to a relative index.
const arg1 = arguments[1];
const end: uintptr =
arg1 != Undefined ? ConvertToRelativeIndex(arg1, length) : length;
arg1 != Undefined ? ConvertAndClampRelativeIndex(arg1, length) : length;
if (end <= start) {
return kEmptyString;

View File

@ -20,7 +20,7 @@ transitioning javascript builtin StringPrototypeSubstr(
// 6. If intStart < 0, set intStart to max(size + intStart, 0).
const start = arguments[0];
const initStart: uintptr =
start != Undefined ? ConvertToRelativeIndex(start, size) : 0;
start != Undefined ? ConvertAndClampRelativeIndex(start, size) : 0;
// 4. If length is undefined,
// let end be +∞; otherwise let end be ? ToInteger(length).

View File

@ -76,7 +76,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice(
// else let k be min(relativeStart, len).
const start = arguments[0];
const k: uintptr =
start != Undefined ? ConvertToRelativeIndex(start, len) : 0;
start != Undefined ? ConvertAndClampRelativeIndex(start, len) : 0;
// 6. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end).
@ -84,7 +84,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice(
// else let final be min(relativeEnd, len).
const end = arguments[1];
let final: uintptr =
end != Undefined ? ConvertToRelativeIndex(end, len) : len;
end != Undefined ? ConvertAndClampRelativeIndex(end, len) : len;
// 8. Let count be max(final - k, 0).
let count: uintptr = Unsigned(IntPtrMax(Signed(final - k), 0));

View File

@ -35,15 +35,16 @@ transitioning javascript builtin TypedArrayPrototypeSubArray(
// srcLength).
const arg0 = arguments[0];
const begin: uintptr =
arg0 != Undefined ? ConvertToRelativeIndex(arg0, srcLength) : 0;
arg0 != Undefined ? ConvertAndClampRelativeIndex(arg0, srcLength) : 0;
// 10. If end is undefined, let relativeEnd be srcLength;
// else, let relativeEnd be ? ToInteger(end).
// 11. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd),
// 0); else let endIndex be min(relativeEnd, srcLength).
const arg1 = arguments[1];
const end: uintptr =
arg1 != Undefined ? ConvertToRelativeIndex(arg1, srcLength) : srcLength;
const end: uintptr = arg1 != Undefined ?
ConvertAndClampRelativeIndex(arg1, srcLength) :
srcLength;
// 12. Let newLength be max(endIndex - beginIndex, 0).
const newLength: uintptr = Unsigned(IntPtrMax(Signed(end - begin), 0));

View File

@ -318,7 +318,7 @@ TEST(IsValidPositiveSmi) {
#endif
}
TEST(ConvertToRelativeIndex) {
TEST(ConvertAndClampRelativeIndex) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 3;
@ -335,7 +335,7 @@ TEST(ConvertToRelativeIndex) {
TNode<UintPtrT> expected =
m.ChangeUintPtrNumberToUintPtr(expected_relative_index);
TNode<UintPtrT> result = m.ConvertToRelativeIndex(index, length);
TNode<UintPtrT> result = m.ConvertAndClampRelativeIndex(index, length);
m.Return(m.SelectBooleanConstant(m.WordEqual(result, expected)));
}