Commit 71ac9e0e authored by Franziska Hinkelmann's avatar Franziska Hinkelmann Committed by Commit Bot

[runtime] Port TypedArrayPrototypeSet to C++

Bug: v8:6704
Change-Id: If636bdd682d76a6d58d36fc9bfbf1302a32468ab
Reviewed-on: https://chromium-review.googlesource.com/641671
Commit-Queue: Franziska Hinkelmann <franzih@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47732}
parent b1409cb8
...@@ -250,50 +250,12 @@ TYPED_ARRAYS(TYPED_ARRAY_SUBARRAY_CASE) ...@@ -250,50 +250,12 @@ TYPED_ARRAYS(TYPED_ARRAY_SUBARRAY_CASE)
%SetForceInlineFlag(GlobalTypedArray.prototype.subarray); %SetForceInlineFlag(GlobalTypedArray.prototype.subarray);
// 22.2.3.23%TypedArray%.prototype.set ( overloaded [ , offset ] )
DEFINE_METHOD_LEN( DEFINE_METHOD_LEN(
GlobalTypedArray.prototype, GlobalTypedArray.prototype,
set(obj, offset) { set(obj, offset) {
var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset); // TODO(franzih): Migrate this to a proper builtin.
if (intOffset < 0) throw %make_range_error(kTypedArraySetNegativeOffset); %_TypedArrayPrototypeSet(this, obj, offset);
if (intOffset > %_MaxSmi()) {
throw %make_range_error(kTypedArraySetSourceTooLarge);
}
switch (%TypedArraySetFastCases(this, obj, intOffset)) {
// These numbers should be synchronized with runtime-typedarray.cc.
case 0: // TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE
return;
case 1: // TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING
%_TypedArraySetFromOverlapping(this, obj, intOffset);
return;
case 2: // TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING
if (intOffset === 0) {
%TypedArrayCopyElements(this, obj, %_TypedArrayGetLength(obj));
} else {
%_TypedArraySetFromArrayLike(
this, obj, %_TypedArrayGetLength(obj), intOffset);
}
return;
case 3: // TYPED_ARRAY_SET_NON_TYPED_ARRAY
var l = obj.length;
if (IS_UNDEFINED(l)) {
if (IS_NUMBER(obj)) {
// 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 %make_type_error(kInvalidArgument);
}
return;
}
l = TO_LENGTH(l);
if (intOffset + l > %_TypedArrayGetLength(this)) {
throw %make_range_error(kTypedArraySetSourceTooLarge);
}
%_TypedArraySetFromArrayLike(this, obj, l, intOffset);
return;
}
}, },
1 /* Set function length. */ 1 /* Set function length. */
); );
......
...@@ -52,20 +52,25 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { ...@@ -52,20 +52,25 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
namespace {
Object* TypedArrayCopyElements(Handle<JSTypedArray> target,
Handle<JSReceiver> source, Object* length_obj) {
size_t length;
CHECK(TryNumberToSize(length_obj, &length));
ElementsAccessor* accessor = target->GetElementsAccessor();
return accessor->CopyElements(source, target, length);
}
} // anonymous namespace
RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) { RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(3, args.length()); DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, destination, 0); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2); CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
size_t length; return TypedArrayCopyElements(target, source, *length_obj);
CHECK(TryNumberToSize(*length_obj, &length));
Handle<JSTypedArray> destination_ta = Handle<JSTypedArray>::cast(destination);
ElementsAccessor* accessor = destination_ta->GetElementsAccessor();
return accessor->CopyElements(source, destination, length);
} }
#define BUFFER_VIEW_GETTER(Type, getter, accessor) \ #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
...@@ -95,64 +100,50 @@ RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { ...@@ -95,64 +100,50 @@ RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
return *holder->GetBuffer(); return *holder->GetBuffer();
} }
// Return codes for Runtime_TypedArraySetFastCases.
// Should be synchronized with typedarray.js natives.
enum TypedArraySetResultCodes { enum TypedArraySetResultCodes {
// Set from typed array of the same type. // Set from typed array of the same type.
// This is processed by TypedArraySetFastCases // This is processed by TypedArraySetFastCases
TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE,
// Set from typed array of the different type, overlapping in memory. // Set from typed array of the different type, overlapping in memory.
TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING,
// Set from typed array of the different type, non-overlapping. // Set from typed array of the different type, non-overlapping.
TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING,
// Set from non-typed array. // Set from non-typed array.
TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 TYPED_ARRAY_SET_NON_TYPED_ARRAY
}; };
// TypedArraySetFromArrayLike(target, source, source_length, offset); namespace {
RUNTIME_FUNCTION(Runtime_TypedArraySetFromArrayLike) { MaybeHandle<Object> TypedArraySetFromArrayLike(Isolate* isolate,
HandleScope scope(isolate); Handle<JSTypedArray> target,
DCHECK_EQ(4, args.length()); Handle<Object> source,
int source_length, int offset) {
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, source, 1);
CONVERT_INT32_ARG_CHECKED(source_length, 2);
DCHECK_GE(source_length, 0); DCHECK_GE(source_length, 0);
CONVERT_INT32_ARG_CHECKED(offset, 3);
DCHECK_GE(offset, 0); DCHECK_GE(offset, 0);
for (int i = 0; i < source_length; i++) { for (int i = 0; i < source_length; i++) {
Handle<Object> value; Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
Object::GetElement(isolate, source, i)); Object::GetElement(isolate, source, i), Object);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
isolate, value, Object::SetElement(isolate, target, offset + i,
Object::SetElement(isolate, target, offset + i, value, value, LanguageMode::STRICT),
LanguageMode::STRICT)); Object);
} }
return *target; return target;
} }
// TypedArraySetFromOverlappingTypedArray(target, source, offset); MaybeHandle<Object> TypedArraySetFromOverlapping(Isolate* isolate,
RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) { Handle<JSTypedArray> target,
HandleScope scope(isolate); Handle<JSTypedArray> source,
DCHECK_EQ(3, args.length()); int offset) {
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source, 1);
CONVERT_INT32_ARG_CHECKED(offset, 2);
DCHECK_GE(offset, 0); DCHECK_GE(offset, 0);
size_t sourceElementSize = source->element_size(); size_t sourceElementSize = source->element_size();
size_t targetElementSize = target->element_size(); size_t targetElementSize = target->element_size();
uint32_t source_length = source->length_value(); uint32_t source_length = source->length_value();
if (source_length == 0) return *target; if (source_length == 0) return target;
// Copy left part. // Copy left part.
...@@ -170,12 +161,14 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) { ...@@ -170,12 +161,14 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) {
for (left_index = 0; left_index < source_length && target_ptr <= source_ptr; for (left_index = 0; left_index < source_length && target_ptr <= source_ptr;
left_index++) { left_index++) {
Handle<Object> value; Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
isolate, value, Object::GetElement(isolate, source, left_index)); Object::GetElement(isolate, source, left_index),
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( Object);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, isolate, value,
Object::SetElement(isolate, target, offset + left_index, value, Object::SetElement(isolate, target, offset + left_index, value,
LanguageMode::STRICT)); LanguageMode::STRICT),
Object);
target_ptr += targetElementSize; target_ptr += targetElementSize;
source_ptr += sourceElementSize; source_ptr += sourceElementSize;
...@@ -196,12 +189,14 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) { ...@@ -196,12 +189,14 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) {
for (right_index = source_length - 1; for (right_index = source_length - 1;
right_index > left_index && target_ptr >= source_ptr; right_index--) { right_index > left_index && target_ptr >= source_ptr; right_index--) {
Handle<Object> value; Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
isolate, value, Object::GetElement(isolate, source, right_index)); Object::GetElement(isolate, source, right_index),
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( Object);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, isolate, value,
Object::SetElement(isolate, target, offset + right_index, value, Object::SetElement(isolate, target, offset + right_index, value,
LanguageMode::STRICT)); LanguageMode::STRICT),
Object);
target_ptr -= targetElementSize; target_ptr -= targetElementSize;
source_ptr -= sourceElementSize; source_ptr -= sourceElementSize;
...@@ -211,38 +206,34 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) { ...@@ -211,38 +206,34 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFromOverlapping) {
for (uint32_t i = left_index; i <= right_index; i++) { for (uint32_t i = left_index; i <= right_index; i++) {
Handle<Object> value; Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
Object::GetElement(isolate, source, i)); Object::GetElement(isolate, source, i), Object);
temp[i - left_index] = value; temp[i - left_index] = value;
} }
for (uint32_t i = left_index; i <= right_index; i++) { for (uint32_t i = left_index; i <= right_index; i++) {
Handle<Object> value; Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, isolate, value,
Object::SetElement(isolate, target, offset + i, temp[i - left_index], Object::SetElement(isolate, target, offset + i, temp[i - left_index],
LanguageMode::STRICT)); LanguageMode::STRICT),
Object);
} }
return *target; return target;
} }
RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { MaybeHandle<Smi> TypedArraySetFastCases(Isolate* isolate,
HandleScope scope(isolate); Handle<JSTypedArray> target,
DCHECK_EQ(3, args.length()); Handle<Object> source_obj,
if (!args[0]->IsJSTypedArray()) { Handle<Object> offset_obj) {
THROW_NEW_ERROR_RETURN_FAILURE( if (!source_obj->IsJSTypedArray()) {
isolate, NewTypeError(MessageTemplate::kNotTypedArray)); return MaybeHandle<Smi>(Smi::FromEnum(TYPED_ARRAY_SET_NON_TYPED_ARRAY),
} isolate);
if (!args[1]->IsJSTypedArray()) {
return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
} }
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0); Handle<JSTypedArray> source = Handle<JSTypedArray>::cast(source_obj);
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source, 1);
CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
size_t offset = 0; size_t offset = 0;
CHECK(TryNumberToSize(*offset_obj, &offset)); CHECK(TryNumberToSize(*offset_obj, &offset));
...@@ -252,8 +243,9 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { ...@@ -252,8 +243,9 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
size_t source_byte_length = NumberToSize(source->byte_length()); size_t source_byte_length = NumberToSize(source->byte_length());
if (offset > target_length || offset + source_length > target_length || if (offset > target_length || offset + source_length > target_length ||
offset + source_length < offset) { // overflow offset + source_length < offset) { // overflow
THROW_NEW_ERROR_RETURN_FAILURE( THROW_NEW_ERROR(
isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge)); isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge),
Smi);
} }
size_t target_offset = NumberToSize(target->byte_offset()); size_t target_offset = NumberToSize(target->byte_offset());
...@@ -269,7 +261,8 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { ...@@ -269,7 +261,8 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
if (target->type() == source->type()) { if (target->type() == source->type()) {
memmove(target_base + offset * target->element_size(), source_base, memmove(target_base + offset * target->element_size(), source_base,
source_byte_length); source_byte_length);
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); return MaybeHandle<Smi>(
Smi::FromEnum(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE), isolate);
} }
// Typed arrays of different types over the same backing store // Typed arrays of different types over the same backing store
...@@ -280,10 +273,120 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { ...@@ -280,10 +273,120 @@ RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
// We do not support overlapping ArrayBuffers // We do not support overlapping ArrayBuffers
DCHECK(target->GetBuffer()->backing_store() == DCHECK(target->GetBuffer()->backing_store() ==
source->GetBuffer()->backing_store()); source->GetBuffer()->backing_store());
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); return MaybeHandle<Smi>(
Smi::FromEnum(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING), isolate);
} else { // Non-overlapping typed arrays } else { // Non-overlapping typed arrays
return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); return MaybeHandle<Smi>(
Smi::FromEnum(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING), isolate);
}
}
} // anonymous namespace
// 22.2.3.23%TypedArray%.prototype.set ( overloaded [ , offset ] )
RUNTIME_FUNCTION(Runtime_TypedArrayPrototypeSet) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, target, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, obj, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, offset, 2);
if (offset->IsUndefined(isolate)) {
offset = Handle<Object>(Smi::kZero, isolate);
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset,
Object::ToInteger(isolate, offset));
}
if (offset->Number() < 0) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kTypedArraySetNegativeOffset));
}
if (offset->Number() > Smi::kMaxValue) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
}
if (!target->IsJSTypedArray()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotTypedArray));
} }
auto int_offset = static_cast<int>(offset->Number());
Handle<Smi> result_code;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result_code,
TypedArraySetFastCases(isolate, Handle<JSTypedArray>::cast(target), obj,
offset));
switch (static_cast<TypedArraySetResultCodes>(result_code->value())) {
case TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE: {
break;
}
case TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING: {
RETURN_FAILURE_ON_EXCEPTION(
isolate, TypedArraySetFromOverlapping(
isolate, Handle<JSTypedArray>::cast(target),
Handle<JSTypedArray>::cast(obj), int_offset));
break;
}
case TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING: {
if (int_offset == 0) {
TypedArrayCopyElements(Handle<JSTypedArray>::cast(target),
Handle<JSTypedArray>::cast(obj),
Handle<JSTypedArray>::cast(obj)->length());
} else {
RETURN_FAILURE_ON_EXCEPTION(
isolate,
TypedArraySetFromArrayLike(
isolate, Handle<JSTypedArray>::cast(target), obj,
Handle<JSTypedArray>::cast(obj)->length_value(), int_offset));
}
break;
}
case TYPED_ARRAY_SET_NON_TYPED_ARRAY: {
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(obj, isolate->factory()->length_string()));
if (len->IsUndefined(isolate)) {
break;
}
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
Object::ToLength(isolate, len));
uint32_t int_l;
CHECK(len->ToUint32(&int_l));
DCHECK_GE(int_offset, 0);
if (static_cast<uint32_t>(int_offset) + int_l >
Handle<JSTypedArray>::cast(target)->length_value()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
}
RETURN_FAILURE_ON_EXCEPTION(
isolate, TypedArraySetFromArrayLike(
isolate, Handle<JSTypedArray>::cast(target), obj, int_l,
int_offset));
} break;
default:
UNREACHABLE();
}
return *target;
} }
namespace { namespace {
......
...@@ -623,9 +623,7 @@ namespace internal { ...@@ -623,9 +623,7 @@ namespace internal {
F(ArrayBufferViewWasNeutered, 1, 1) \ F(ArrayBufferViewWasNeutered, 1, 1) \
F(TypedArrayGetLength, 1, 1) \ F(TypedArrayGetLength, 1, 1) \
F(TypedArrayGetBuffer, 1, 1) \ F(TypedArrayGetBuffer, 1, 1) \
F(TypedArraySetFromArrayLike, 4, 1) \ F(TypedArrayPrototypeSet, 3, 1) \
F(TypedArraySetFromOverlapping, 3, 1) \
F(TypedArraySetFastCases, 3, 1) \
F(TypedArraySortFast, 1, 1) \ F(TypedArraySortFast, 1, 1) \
F(TypedArrayMaxSizeInHeap, 0, 1) \ F(TypedArrayMaxSizeInHeap, 0, 1) \
F(IsTypedArray, 1, 1) \ F(IsTypedArray, 1, 1) \
......
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