Commit 978506c3 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by V8 LUCI CQ

[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/+/3669655Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80786}
parent 5299e11b
...@@ -3,25 +3,39 @@ ...@@ -3,25 +3,39 @@
// found in the LICENSE file. // found in the LICENSE file.
namespace array { 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 // https://tc39.es/proposal-item-method/#sec-array.prototype.at
transitioning javascript builtin ArrayPrototypeAt( transitioning javascript builtin ArrayPrototypeAt(
js-implicit context: NativeContext, receiver: JSAny)(index: JSAny): JSAny { js-implicit context: NativeContext, receiver: JSAny)(index: JSAny): JSAny {
// 1. Let O be ? ToObject(this value). // 1. Let O be ? ToObject(this value).
const o = ToObject_Inline(context, receiver); const o = ToObject_Inline(context, receiver);
// 2. Let len be ? LengthOfArrayLike(O). // 2. Let len be ? LengthOfArrayLike(O).
const len = GetLengthProperty(o); const len = GetLengthProperty(o);
try {
// 3. Let relativeIndex be ? ToInteger(index). // 3. Let relativeIndex be ? ToInteger(index).
const relativeIndex = ToInteger_Inline(index); const relativeIndex = ToInteger_Inline(index);
// 4. If relativeIndex ≥ 0, then // 4. If relativeIndex ≥ 0, then
// a. Let k be relativeIndex. // a. Let k be relativeIndex.
// 5. Else, // 5. Else,
// a. Let k be len + relativeIndex. // a. Let k be len + relativeIndex.
const k = relativeIndex >= 0 ? relativeIndex : 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. // 6. If k < 0 or k ≥ len, then return undefined.
if (k < 0 || k >= len) {
return Undefined; return Undefined;
} }
// 7. Return ? Get(O, ! ToString(k)).
return GetProperty(o, k);
} }
} }
...@@ -3,8 +3,15 @@ ...@@ -3,8 +3,15 @@
// found in the LICENSE file. // found in the LICENSE file.
namespace array { namespace array {
macro ConvertToRelativeIndex(index: Number, length: Number): Number { macro ConvertAndClampRelativeIndex(index: Number, length: Number): Number {
return index < 0 ? Max(index + length, 0) : Min(index, length); 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 // https://tc39.github.io/ecma262/#sec-array.prototype.copyWithin
...@@ -21,14 +28,14 @@ transitioning javascript builtin ArrayPrototypeCopyWithin( ...@@ -21,14 +28,14 @@ transitioning javascript builtin ArrayPrototypeCopyWithin(
// 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); // 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0);
// else let to be min(relativeTarget, len). // 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). // 5. Let relativeStart be ? ToInteger(start).
const relativeStart: Number = ToInteger_Inline(arguments[1]); const relativeStart: Number = ToInteger_Inline(arguments[1]);
// 6. If relativeStart < 0, let from be max((len + relativeStart), 0); // 6. If relativeStart < 0, let from be max((len + relativeStart), 0);
// else let from be min(relativeStart, len). // 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; // 7. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end). // else let relativeEnd be ? ToInteger(end).
...@@ -39,7 +46,7 @@ transitioning javascript builtin ArrayPrototypeCopyWithin( ...@@ -39,7 +46,7 @@ transitioning javascript builtin ArrayPrototypeCopyWithin(
// 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); // 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0);
// else let final be min(relativeEnd, len). // 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). // 9. Let count be min(final-from, len-to).
let count: Number = Min(final - from, length - to); let count: Number = Min(final - from, length - to);
......
...@@ -1643,44 +1643,65 @@ extern macro IsOneByteStringInstanceType(InstanceType): bool; ...@@ -1643,44 +1643,65 @@ extern macro IsOneByteStringInstanceType(InstanceType): bool;
// After converting an index to an integer, calculate a relative index: // After converting an index to an integer, calculate a relative index:
// return index < 0 ? max(length + index, 0) : min(index, length) // return index < 0 ? max(length + index, 0) : min(index, length)
@export @export
transitioning macro ConvertToRelativeIndex(implicit context: Context)( transitioning macro ConvertAndClampRelativeIndex(implicit context: Context)(
index: JSAny, length: uintptr): uintptr { index: JSAny, length: uintptr): uintptr {
const indexNumber: Number = ToInteger_Inline(index); const indexNumber: Number = ToInteger_Inline(index);
return ConvertToRelativeIndex(indexNumber, length); return ConvertAndClampRelativeIndex(indexNumber, length);
} }
// Calculate a relative index: // Calculate a relative index:
// return index < 0 ? max(length + index, 0) : min(index, length) // return index < 0 ? max(length + index, 0) : min(index, length)
@export @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) { typeswitch (indexNumber) {
case (indexSmi: Smi): { case (indexSmi: Smi): {
const indexIntPtr: intptr = Convert<intptr>(indexSmi); const indexIntPtr: intptr = Convert<intptr>(indexSmi);
// The logic is implemented using unsigned types. // The logic is implemented using unsigned types.
if (indexIntPtr < 0) { if (indexIntPtr < 0) {
const relativeIndex: uintptr = Unsigned(indexIntPtr) + length; const relativeIndex: uintptr = Unsigned(indexIntPtr) + length;
return relativeIndex < length ? relativeIndex : 0; if (relativeIndex < length) return relativeIndex;
goto OutOfBoundsLow;
} else { } else {
const relativeIndex: uintptr = Unsigned(indexIntPtr); const relativeIndex: uintptr = Unsigned(indexIntPtr);
return relativeIndex < length ? relativeIndex : length; if (relativeIndex < length) return relativeIndex;
goto OutOfBoundsHigh;
} }
} }
case (indexHeapNumber: HeapNumber): { case (indexHeapNumber: HeapNumber): {
dcheck(IsNumberNormalized(indexHeapNumber)); dcheck(IsNumberNormalized(indexHeapNumber));
const indexDouble: float64 = Convert<float64>(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. // above accepting JSAny indices.
dcheck(!Float64IsNaN(indexDouble)); dcheck(!Float64IsNaN(indexDouble));
const lengthDouble: float64 = Convert<float64>(length); const lengthDouble: float64 = Convert<float64>(length);
dcheck(lengthDouble <= kMaxSafeInteger); dcheck(lengthDouble <= kMaxSafeInteger);
if (indexDouble < 0) { if (indexDouble < 0) {
const relativeIndex: float64 = lengthDouble + indexDouble; const relativeIndex: float64 = lengthDouble + indexDouble;
return relativeIndex > 0 ? ChangeFloat64ToUintPtr(relativeIndex) : 0; if (relativeIndex > 0) {
return ChangeFloat64ToUintPtr(relativeIndex);
}
goto OutOfBoundsLow;
} else { } else {
return ChangeFloat64ToUintPtr( if (indexDouble < lengthDouble) {
indexDouble < lengthDouble ? indexDouble : lengthDouble); return ChangeFloat64ToUintPtr(indexDouble);
}
goto OutOfBoundsHigh;
} }
} }
} }
......
...@@ -17,13 +17,13 @@ transitioning javascript builtin StringPrototypeSlice( ...@@ -17,13 +17,13 @@ transitioning javascript builtin StringPrototypeSlice(
// Convert {start} to a relative index. // Convert {start} to a relative index.
const arg0 = arguments[0]; const arg0 = arguments[0];
const start: uintptr = const start: uintptr =
arg0 != Undefined ? ConvertToRelativeIndex(arg0, length) : 0; arg0 != Undefined ? ConvertAndClampRelativeIndex(arg0, length) : 0;
// 5. If end is undefined, let intEnd be len; // 5. If end is undefined, let intEnd be len;
// else Convert {end} to a relative index. // else Convert {end} to a relative index.
const arg1 = arguments[1]; const arg1 = arguments[1];
const end: uintptr = const end: uintptr =
arg1 != Undefined ? ConvertToRelativeIndex(arg1, length) : length; arg1 != Undefined ? ConvertAndClampRelativeIndex(arg1, length) : length;
if (end <= start) { if (end <= start) {
return kEmptyString; return kEmptyString;
......
...@@ -20,7 +20,7 @@ transitioning javascript builtin StringPrototypeSubstr( ...@@ -20,7 +20,7 @@ transitioning javascript builtin StringPrototypeSubstr(
// 6. If intStart < 0, set intStart to max(size + intStart, 0). // 6. If intStart < 0, set intStart to max(size + intStart, 0).
const start = arguments[0]; const start = arguments[0];
const initStart: uintptr = const initStart: uintptr =
start != Undefined ? ConvertToRelativeIndex(start, size) : 0; start != Undefined ? ConvertAndClampRelativeIndex(start, size) : 0;
// 4. If length is undefined, // 4. If length is undefined,
// let end be +∞; otherwise let end be ? ToInteger(length). // let end be +∞; otherwise let end be ? ToInteger(length).
......
...@@ -76,7 +76,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice( ...@@ -76,7 +76,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice(
// else let k be min(relativeStart, len). // else let k be min(relativeStart, len).
const start = arguments[0]; const start = arguments[0];
const k: uintptr = const k: uintptr =
start != Undefined ? ConvertToRelativeIndex(start, len) : 0; start != Undefined ? ConvertAndClampRelativeIndex(start, len) : 0;
// 6. If end is undefined, let relativeEnd be len; // 6. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end). // else let relativeEnd be ? ToInteger(end).
...@@ -84,7 +84,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice( ...@@ -84,7 +84,7 @@ transitioning javascript builtin TypedArrayPrototypeSlice(
// else let final be min(relativeEnd, len). // else let final be min(relativeEnd, len).
const end = arguments[1]; const end = arguments[1];
let final: uintptr = let final: uintptr =
end != Undefined ? ConvertToRelativeIndex(end, len) : len; end != Undefined ? ConvertAndClampRelativeIndex(end, len) : len;
// 8. Let count be max(final - k, 0). // 8. Let count be max(final - k, 0).
let count: uintptr = Unsigned(IntPtrMax(Signed(final - k), 0)); let count: uintptr = Unsigned(IntPtrMax(Signed(final - k), 0));
......
...@@ -35,15 +35,16 @@ transitioning javascript builtin TypedArrayPrototypeSubArray( ...@@ -35,15 +35,16 @@ transitioning javascript builtin TypedArrayPrototypeSubArray(
// srcLength). // srcLength).
const arg0 = arguments[0]; const arg0 = arguments[0];
const begin: uintptr = const begin: uintptr =
arg0 != Undefined ? ConvertToRelativeIndex(arg0, srcLength) : 0; arg0 != Undefined ? ConvertAndClampRelativeIndex(arg0, srcLength) : 0;
// 10. If end is undefined, let relativeEnd be srcLength; // 10. If end is undefined, let relativeEnd be srcLength;
// else, let relativeEnd be ? ToInteger(end). // else, let relativeEnd be ? ToInteger(end).
// 11. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), // 11. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd),
// 0); else let endIndex be min(relativeEnd, srcLength). // 0); else let endIndex be min(relativeEnd, srcLength).
const arg1 = arguments[1]; const arg1 = arguments[1];
const end: uintptr = const end: uintptr = arg1 != Undefined ?
arg1 != Undefined ? ConvertToRelativeIndex(arg1, srcLength) : srcLength; ConvertAndClampRelativeIndex(arg1, srcLength) :
srcLength;
// 12. Let newLength be max(endIndex - beginIndex, 0). // 12. Let newLength be max(endIndex - beginIndex, 0).
const newLength: uintptr = Unsigned(IntPtrMax(Signed(end - begin), 0)); const newLength: uintptr = Unsigned(IntPtrMax(Signed(end - begin), 0));
......
...@@ -318,7 +318,7 @@ TEST(IsValidPositiveSmi) { ...@@ -318,7 +318,7 @@ TEST(IsValidPositiveSmi) {
#endif #endif
} }
TEST(ConvertToRelativeIndex) { TEST(ConvertAndClampRelativeIndex) {
Isolate* isolate(CcTest::InitIsolateOnce()); Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 3; const int kNumParams = 3;
...@@ -335,7 +335,7 @@ TEST(ConvertToRelativeIndex) { ...@@ -335,7 +335,7 @@ TEST(ConvertToRelativeIndex) {
TNode<UintPtrT> expected = TNode<UintPtrT> expected =
m.ChangeUintPtrNumberToUintPtr(expected_relative_index); 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))); m.Return(m.SelectBooleanConstant(m.WordEqual(result, expected)));
} }
......
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