Commit e309b2d9 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[builtins] Port %TypedArray%.prototype.set to Torque

... in an uintptr friendly way.

Drive-by-fix:
1) IsForceSlowPath() check is integrated into Cast<FastJSArray>
2) disable tests incompatible with --force-slow-path in "slow_path" variant

Bug: v8:8906, v8:4153
Change-Id: I427f117073bc295120aa52fb3fe023ee04d58302
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1899988
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64799}
parent d5303952
......@@ -1001,6 +1001,7 @@ torque_files = [
"src/builtins/typed-array-of.tq",
"src/builtins/typed-array-reduce.tq",
"src/builtins/typed-array-reduceright.tq",
"src/builtins/typed-array-set.tq",
"src/builtins/typed-array-slice.tq",
"src/builtins/typed-array-some.tq",
"src/builtins/typed-array-subarray.tq",
......
......@@ -1419,6 +1419,11 @@ const kArrayBufferMaxByteLength:
constexpr uintptr generates 'JSArrayBuffer::kMaxByteLength';
const kMaxTypedArrayInHeap:
constexpr int31 generates 'JSTypedArray::kMaxSizeInHeap';
// CSA does not support 64-bit types on 32-bit platforms so as a workaround the
// kMaxSafeIntegerUint64 is defined as uintptr and allowed to be used only
// inside if constexpr (Is64()) i.e. on 64-bit architectures.
const kMaxSafeIntegerUint64: constexpr uintptr
generates 'static_cast<uintptr_t>(kMaxSafeIntegerUint64)';
const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger';
const kMaxUInt32Double: constexpr float64 generates 'kMaxUInt32Double';
const kSmiMaxValue: constexpr uintptr generates 'kSmiMaxValue';
......@@ -1463,6 +1468,10 @@ const kInvalidDataViewAccessorOffset: constexpr MessageTemplate
generates 'MessageTemplate::kInvalidDataViewAccessorOffset';
const kStrictReadOnlyProperty: constexpr MessageTemplate
generates 'MessageTemplate::kStrictReadOnlyProperty';
const kTypedArraySetOffsetOutOfBounds: constexpr MessageTemplate
generates 'MessageTemplate::kTypedArraySetOffsetOutOfBounds';
const kInvalidArgument: constexpr MessageTemplate
generates 'MessageTemplate::kInvalidArgument';
const kString: constexpr PrimitiveType
generates 'PrimitiveType::kString';
......@@ -2036,6 +2045,9 @@ extern macro IsElementsKindLessThanOrEqual(
ElementsKind, constexpr ElementsKind): bool;
extern macro IsElementsKindGreaterThan(
ElementsKind, constexpr ElementsKind): bool;
extern macro IsElementsKindInRange(
ElementsKind, constexpr ElementsKind, constexpr ElementsKind): bool;
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
......@@ -2694,6 +2706,8 @@ Cast<FastJSRegExp>(implicit context: Context)(o: HeapObject): FastJSRegExp
Cast<FastJSArray>(implicit context: Context)(o: HeapObject): FastJSArray
labels CastError {
if (IsForceSlowPath()) goto CastError;
const map: Map = o.map;
if (!IsJSArrayMap(map)) goto CastError;
......@@ -3727,6 +3741,28 @@ macro SameValue(a: JSAny, b: JSAny): bool {
BranchIfSameValue(a, b) otherwise return true, return false;
}
// Does "if (index1 + index2 > limit) goto IfOverflow" in an uintptr overflow
// friendly way where index1 and index2 are in [0, kMaxSafeInteger] range.
macro CheckIntegerIndexAdditionOverflow(
index1: uintptr, index2: uintptr, limit: uintptr) labels IfOverflow {
if constexpr (Is64()) {
assert(index1 <= kMaxSafeIntegerUint64);
assert(index2 <= kMaxSafeIntegerUint64);
// Given that both index1 and index2 are in a safe integer range the
// addition can't overflow.
if (index1 + index2 > limit) goto IfOverflow;
} else {
// Uintptr range is "smaller" than [0, kMaxSafeInteger] range, so
// "index1 + index2" may overflow, so we check the condition in the
// following way "if (index1 > limit - index2) goto IfOverflow" and check
// that "limit - index2" does not underflow.
const index1Limit = limit - index2;
if (index1 > index1Limit) goto IfOverflow;
// Handle potential index1Limit underflow.
if (index1Limit > limit) goto IfOverflow;
}
}
// TODO(tebbi): Define enum here once they appear in Torque.
//
// The value is a SafeInteger that fits into uintptr range, so no bounds checks
......@@ -3808,6 +3844,14 @@ macro ChangeSafeIntegerNumberToUintPtr(value: Number):
}
}
transitioning macro ToUintPtr(implicit context: Context)(value: JSAny):
uintptr labels IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow {
if (value == Undefined) return 0;
const indexNumber = ToInteger_Inline(context, value, kTruncateMinusZero);
return TryNumberToUintPtr(indexNumber, kModeValueIsAnyNumber)
otherwise IfLessThanZero, IfUIntPtrOverflow, IfSafeIntegerOverflow;
}
// https://tc39.github.io/ecma262/#sec-toindex
// Unlike ToIndex from the spec this implementation triggers IfRangeError if
// the result is bigger than min(kMaxUIntPtr, kMaxSafeInteger).
......
......@@ -932,8 +932,6 @@ namespace internal {
CPP(TypedArrayPrototypeLastIndexOf) \
/* ES6 #sec-%typedarray%.prototype.reverse */ \
CPP(TypedArrayPrototypeReverse) \
/* ES6 %TypedArray%.prototype.set */ \
TFJ(TypedArrayPrototypeSet, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-get-%typedarray%.prototype-@@tostringtag */ \
TFJ(TypedArrayPrototypeToStringTag, 0, kReceiver) \
/* ES6 %TypedArray%.prototype.map */ \
......
This diff is collapsed.
......@@ -35,13 +35,13 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<UintPtrT> byte_offset);
// Returns true if kind is either UINT8_ELEMENTS or UINT8_CLAMPED_ELEMENTS.
TNode<BoolT> IsUint8ElementsKind(TNode<Word32T> kind);
TNode<BoolT> IsUint8ElementsKind(TNode<Int32T> kind);
// Returns true if kind is either BIGINT64_ELEMENTS or BIGUINT64_ELEMENTS.
TNode<BoolT> IsBigInt64ElementsKind(TNode<Word32T> kind);
TNode<BoolT> IsBigInt64ElementsKind(TNode<Int32T> kind);
// Returns the byte size of an element for a TypedArray elements kind.
TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
TNode<IntPtrT> GetTypedArrayElementSize(TNode<Int32T> elements_kind);
// Returns information (byte size and map) about a TypedArray's elements.
ElementsInfo GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array);
......@@ -57,16 +57,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<Object> obj,
const char* method_name);
// Fast path for setting a TypedArray (source) onto another TypedArray
// (target) at an element offset.
void SetTypedArraySource(TNode<Context> context, TNode<JSTypedArray> source,
TNode<JSTypedArray> target, TNode<IntPtrT> offset,
Label* call_runtime, Label* if_source_too_large);
void SetJSArraySource(TNode<Context> context, TNode<JSArray> source,
TNode<JSTypedArray> target, TNode<IntPtrT> offset,
Label* call_runtime, Label* if_source_too_large);
void CallCMemmove(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length);
......@@ -78,12 +68,12 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
void CallCCopyFastNumberJSArrayElementsToTypedArray(
TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
TNode<IntPtrT> source_length, TNode<IntPtrT> offset);
TNode<UintPtrT> source_length, TNode<UintPtrT> offset);
void CallCCopyTypedArrayElementsToTypedArray(TNode<JSTypedArray> source,
TNode<JSTypedArray> dest,
TNode<IntPtrT> source_length,
TNode<IntPtrT> offset);
TNode<UintPtrT> source_length,
TNode<UintPtrT> offset);
void CallCCopyTypedArrayElementsSlice(TNode<JSTypedArray> source,
TNode<JSTypedArray> dest,
......
......@@ -390,21 +390,8 @@ namespace data_view {
const elementSize: uintptr = DataViewElementSize(kind);
// 10. If getIndex + elementSize > viewSize, throw a RangeError exception.
if constexpr (Is64()) {
// Given that
// a) getIndex is in [0, kMaxSafeInteger] range
// b) elementSize is in [1, 8] range
// the addition can't overflow.
if (getIndex + elementSize > viewSize) goto RangeError;
} else {
// In order to avoid operating on float64s we deal with uintptr values
// and do two comparisons to handle potential uintptr overflow on
// 32-bit architectures.
const lastPossibleElementOffset: uintptr = viewSize - elementSize;
// Check if lastPossibleElementOffset underflowed.
if (lastPossibleElementOffset > viewSize) goto RangeError;
if (getIndex > lastPossibleElementOffset) goto RangeError;
}
CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize)
otherwise RangeError;
// 11. Let bufferIndex be getIndex + viewOffset.
const bufferIndex: uintptr = getIndex + viewOffset;
......@@ -697,21 +684,8 @@ namespace data_view {
const elementSize: uintptr = DataViewElementSize(kind);
// 12. If getIndex + elementSize > viewSize, throw a RangeError exception.
if constexpr (Is64()) {
// Given that
// a) getIndex is in [0, kMaxSafeInteger] range
// b) elementSize is in [1, 8] range
// the addition can't overflow.
if (getIndex + elementSize > viewSize) goto RangeError;
} else {
// In order to avoid operating on float64s we deal with uintptr values
// and do two comparisons to handle potential uintptr overflow on
// 32-bit architectures.
const lastPossibleElementOffset: uintptr = viewSize - elementSize;
// Check if lastPossibleElementOffset underflowed.
if (lastPossibleElementOffset > viewSize) goto RangeError;
if (getIndex > lastPossibleElementOffset) goto RangeError;
}
CheckIntegerIndexAdditionOverflow(getIndex, elementSize, viewSize)
otherwise RangeError;
// 13. Let bufferIndex be getIndex + viewOffset.
const bufferIndex: uintptr = getIndex + viewOffset;
......
......@@ -355,8 +355,7 @@ namespace typed_array {
// 5. Let elementSize be the Number value of the Element Size value in Table
// 56 for constructorName.
const elementsInfo: typed_array::TypedArrayElementsInfo =
typed_array::GetTypedArrayElementsInfo(map);
const elementsInfo = GetTypedArrayElementsInfo(map);
try {
typeswitch (arg1) {
......
This diff is collapsed.
......@@ -73,6 +73,8 @@ namespace typed_array {
JSTypedArray): TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind):
bool;
extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
ElementsKind): bool;
extern macro LoadFixedTypedArrayElementAsTagged(
......
......@@ -1051,7 +1051,8 @@ constexpr uint64_t kHoleNanInt64 =
(static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
// ES6 section 20.1.2.6 Number.MAX_SAFE_INTEGER
constexpr double kMaxSafeInteger = 9007199254740991.0; // 2^53-1
constexpr uint64_t kMaxSafeIntegerUint64 = 9007199254740991; // 2^53-1
constexpr double kMaxSafeInteger = static_cast<double>(kMaxSafeIntegerUint64);
constexpr double kMaxUInt32Double = double{kMaxUInt32};
......
......@@ -4771,6 +4771,8 @@ void CopyFastNumberJSArrayElementsToTypedArray(Address raw_context,
switch (destination.GetElementsKind()) {
#define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype) \
case TYPE##_ELEMENTS: \
/* TODO(v8:4153): handle huge offsets here. */ \
DCHECK_LE(offset, kMaxUInt32); \
CHECK(Type##ElementsAccessor::TryCopyElementsFastNumber( \
context, source, destination, length, static_cast<uint32_t>(offset))); \
break;
......@@ -4790,6 +4792,8 @@ void CopyTypedArrayElementsToTypedArray(Address raw_source,
switch (destination.GetElementsKind()) {
#define TYPED_ARRAYS_CASE(Type, type, TYPE, ctype) \
case TYPE##_ELEMENTS: \
/* TODO(v8:4153): handle huge offsets here. */ \
DCHECK_LE(offset, kMaxUInt32); \
Type##ElementsAccessor::CopyElementsFromTypedArray( \
source, destination, length, static_cast<uint32_t>(offset)); \
break;
......
......@@ -157,7 +157,7 @@ class ElementsAccessor {
virtual Object CopyElements(Handle<Object> source,
Handle<JSObject> destination, size_t length,
uint32_t offset = 0) = 0;
uint32_t offset) = 0;
virtual Handle<FixedArray> CreateListFromArrayLike(Isolate* isolate,
Handle<JSObject> object,
......
......@@ -42,7 +42,7 @@ RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
CHECK(TryNumberToSize(*length_obj, &length));
ElementsAccessor* accessor = target->GetElementsAccessor();
return accessor->CopyElements(source, target, length);
return accessor->CopyElements(source, target, length, 0);
}
RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
......@@ -149,49 +149,25 @@ RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
return *array;
}
// 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )
RUNTIME_FUNCTION(Runtime_TypedArraySet) {
HandleScope scope(isolate);
Handle<JSTypedArray> target = args.at<JSTypedArray>(0);
Handle<Object> obj = args.at(1);
Handle<Smi> offset = args.at<Smi>(2);
DCHECK(!target->WasDetached()); // Checked in TypedArrayPrototypeSet.
DCHECK(!obj->IsJSTypedArray()); // Should be handled by CSA.
DCHECK_LE(0, offset->value());
const uint32_t uint_offset = static_cast<uint32_t>(offset->value());
if (obj->IsNumber()) {
// For number as a first argument, throw TypeError
// instead of silently ignoring the call, so that
// users know they did something wrong.
// (Consistent with Firefox and Blink/WebKit)
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalidArgument));
}
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
Object::ToObject(isolate, obj));
Handle<Object> len;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, len,
Object::GetProperty(isolate, obj, isolate->factory()->length_string()));
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
Object::ToLength(isolate, len));
DCHECK_EQ(4, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, source, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 3);
if (uint_offset + len->Number() > target->length()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
}
size_t length;
CHECK(TryNumberToSize(*length_obj, &length));
uint32_t int_l;
CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
size_t offset;
CHECK(TryNumberToSize(*offset_obj, &offset));
DCHECK_LE(offset, kMaxUInt32);
Handle<JSReceiver> source = Handle<JSReceiver>::cast(obj);
ElementsAccessor* accessor = target->GetElementsAccessor();
return accessor->CopyElements(source, target, int_l, uint_offset);
// TODO(v8:4153): Support huge TypedArrays.
return accessor->CopyElements(source, target, length,
static_cast<uint32_t>(offset));
}
} // namespace internal
......
......@@ -1072,6 +1072,12 @@
# Slow tests.
'regress/regress-crbug-493779': [SKIP],
'string-replace-gc': [SKIP],
}], # variant == slow_path and gc_stress
##############################################################################
['variant == slow_path', {
# Tests that are not compatible with the --force-slow-path mode.
'filter-element-kinds': [SKIP],
}], # variant == slow_path
##############################################################################
......
......@@ -27,7 +27,7 @@ description(
var array = [];
for (var i = 0; i < 20000; ++i)
for (var i = 0; i < 2000; ++i)
array.push(i);
array.sort(function(a, b) {
......
......@@ -150,7 +150,6 @@ namespace array {
let canUseSameAccessorFn: CanUseSameAccessorFn;
try {
if (IsForceSlowPath()) goto Slow;
const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
// Copy copy-on-write (COW) arrays.
......
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