[typedarray] Port TypedArray#slice to Torque.

Bug: v8:8906
Change-Id: I7a07482d2d5de13de11fa2611e3c6ae18439e820
Reviewed-on: https://chromium-review.googlesource.com/c/1493136
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Reviewed-by: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60007}
This commit is contained in:
peterwmwong 2019-03-04 07:31:16 -06:00 committed by Commit Bot
parent 683cf6f43b
commit acdaa4c713
9 changed files with 154 additions and 152 deletions

View File

@ -928,6 +928,7 @@ torque_files = [
"src/builtins/typed-array-foreach.tq",
"src/builtins/typed-array-reduce.tq",
"src/builtins/typed-array-reduceright.tq",
"src/builtins/typed-array-slice.tq",
"src/builtins/typed-array-subarray.tq",
"test/torque/test-torque.tq",
"third_party/v8/builtins/array-sort.tq",
@ -962,6 +963,7 @@ torque_namespaces = [
"typed-array-foreach",
"typed-array-reduce",
"typed-array-reduceright",
"typed-array-slice",
"typed-array-subarray",
]

View File

@ -481,6 +481,10 @@ const kReduceNoInitial: constexpr MessageTemplate
generates 'MessageTemplate::kReduceNoInitial';
const kFirstArgumentNotRegExp: constexpr MessageTemplate
generates 'MessageTemplate::kFirstArgumentNotRegExp';
const kBigIntMixedTypes: constexpr MessageTemplate
generates 'MessageTemplate::kBigIntMixedTypes';
const kTypedArrayTooShort: constexpr MessageTemplate
generates 'MessageTemplate::kTypedArrayTooShort';
const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
@ -846,6 +850,8 @@ extern operator '|' macro Word32Or(int32, int32): int32;
extern operator '|' macro Word32Or(uint32, uint32): uint32;
extern operator '&' macro Word32And(bool, bool): bool;
extern operator '|' macro Word32Or(bool, bool): bool;
extern operator '==' macro Word32Equal(bool, bool): bool;
extern operator '!=' macro Word32NotEqual(bool, bool): bool;
extern operator '+' macro Float64Add(float64, float64): float64;

View File

@ -15,6 +15,7 @@
#include "src/objects/allocation-site-inl.h"
#include "src/objects/arguments-inl.h"
#include "src/objects/property-cell.h"
#include "torque-generated/builtins-typed-array-createtypedarray-from-dsl-gen.h"
namespace v8 {
namespace internal {
@ -96,9 +97,9 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
TNode<Smi> length = CAST(len_);
const char* method_name = "%TypedArray%.prototype.map";
TypedArrayBuiltinsAssembler typedarray_asm(state());
TypedArrayCreatetypedarrayBuiltinsFromDSLAssembler typedarray_asm(state());
TNode<JSTypedArray> a = typedarray_asm.TypedArraySpeciesCreateByLength(
context(), original_array, length, method_name);
context(), method_name, original_array, length);
// In the Spec and our current implementation, the length check is already
// performed in TypedArraySpeciesCreate.
CSA_ASSERT(this, SmiLessThanOrEqual(CAST(len_), LoadJSTypedArrayLength(a)));

View File

@ -1140,9 +1140,6 @@ namespace internal {
CPP(TypedArrayPrototypeReverse) \
/* ES6 %TypedArray%.prototype.set */ \
TFJ(TypedArrayPrototypeSet, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-%typedarray%.prototype.slice */ \
TFJ(TypedArrayPrototypeSlice, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-get-%typedarray%.prototype-@@tostringtag */ \
TFJ(TypedArrayPrototypeToStringTag, 0, kReceiver) \
/* ES6 %TypedArray%.prototype.every */ \

View File

@ -147,9 +147,9 @@ TNode<FixedTypedArrayBase> TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
return CAST(elements);
}
Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
CSA_ASSERT(this, IsJSTypedArray(typed_array));
Node* elements = LoadElements(typed_array);
TNode<RawPtrT> TypedArrayBuiltinsAssembler::LoadDataPtr(
TNode<JSTypedArray> typed_array) {
TNode<FixedArrayBase> elements = LoadElements(typed_array);
CSA_ASSERT(this, IsFixedTypedArray(elements));
return LoadFixedTypedArrayBackingStore(CAST(elements));
}
@ -306,22 +306,6 @@ TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
LoadContextElement(LoadNativeContext(context), context_slot.value()));
}
TNode<JSTypedArray>
TypedArrayBuiltinsAssembler::TypedArraySpeciesCreateByLength(
TNode<Context> context, TNode<JSTypedArray> exemplar, TNode<Smi> len,
const char* method_name) {
CSA_ASSERT(this, TaggedIsPositiveSmi(len));
TypedArrayCreatetypedarrayBuiltinsFromDSLAssembler typedarray_asm(state());
const int31_t kNumArgs = 1;
TNode<JSTypedArray> new_typed_array = typedarray_asm.TypedArraySpeciesCreate(
context, method_name, kNumArgs, exemplar, len, UndefinedConstant(),
UndefinedConstant());
ThrowIfLengthLessThan(context, new_typed_array, len);
return new_typed_array;
}
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArrayCreateByLength(
TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
const char* method_name) {
@ -408,8 +392,8 @@ void TypedArrayBuiltinsAssembler::SetTypedArraySource(
// Grab pointers and byte lengths we need later on.
TNode<IntPtrT> target_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(target));
TNode<IntPtrT> source_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(source));
TNode<RawPtrT> target_data_ptr = LoadDataPtr(target);
TNode<RawPtrT> source_data_ptr = LoadDataPtr(source);
TNode<Word32T> source_el_kind = LoadElementsKind(source);
TNode<Word32T> target_el_kind = LoadElementsKind(target);
@ -434,9 +418,9 @@ void TypedArrayBuiltinsAssembler::SetTypedArraySource(
BIND(&call_memmove);
{
TNode<IntPtrT> target_start =
IntPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
CallCMemmove(target_start, source_data_ptr, source_byte_length);
TNode<RawPtrT> target_start =
RawPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
CallCMemmove(target_start, source_data_ptr, Unsigned(source_byte_length));
Goto(&out);
}
@ -506,9 +490,9 @@ void TypedArrayBuiltinsAssembler::SetJSArraySource(
BIND(&out);
}
void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
TNode<IntPtrT> src_ptr,
TNode<IntPtrT> byte_length) {
void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<RawPtrT> dest_ptr,
TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length) {
TNode<ExternalReference> memmove =
ExternalConstant(ExternalReference::libc_memmove_function());
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
@ -698,118 +682,6 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
ThrowTypeError(context, MessageTemplate::kNotTypedArray);
}
// ES %TypedArray%.prototype.slice
TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
const char* method_name = "%TypedArray%.prototype.slice";
Label call_c(this), call_memmove(this), if_count_is_not_zero(this),
if_bigint_mixed_types(this, Label::kDeferred);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CodeStubArguments args(
this,
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
TNode<Object> receiver = args.GetReceiver();
TNode<JSTypedArray> source =
ValidateTypedArray(context, receiver, method_name);
TNode<Smi> source_length = LoadJSTypedArrayLength(source);
// Convert start offset argument to integer, and calculate relative offset.
TNode<Object> start = args.GetOptionalArgumentValue(0, SmiConstant(0));
TNode<Smi> start_index =
SmiTag(ConvertToRelativeIndex(context, start, SmiUntag(source_length)));
// Convert end offset argument to integer, and calculate relative offset.
// If end offset is not given or undefined is given, set source_length to
// "end_index".
TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
TNode<Smi> end_index =
Select<Smi>(IsUndefined(end), [=] { return source_length; },
[=] {
return SmiTag(ConvertToRelativeIndex(
context, end, SmiUntag(source_length)));
});
// Create a result array by invoking TypedArraySpeciesCreate.
TNode<Smi> count = SmiMax(SmiSub(end_index, start_index), SmiConstant(0));
TNode<JSTypedArray> result_array =
TypedArraySpeciesCreateByLength(context, source, count, method_name);
// If count is zero, return early.
GotoIf(SmiGreaterThan(count, SmiConstant(0)), &if_count_is_not_zero);
args.PopAndReturn(result_array);
BIND(&if_count_is_not_zero);
// Check the source array is detached or not. We don't need to check if the
// result array is detached or not since TypedArraySpeciesCreate checked it.
CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(LoadObjectField(
result_array, JSTypedArray::kBufferOffset))));
TNode<JSArrayBuffer> receiver_buffer =
LoadJSArrayBufferViewBuffer(CAST(receiver));
ThrowIfArrayBufferIsDetached(context, receiver_buffer, method_name);
// result_array could be a different type from source or share the same
// buffer with the source because of custom species constructor.
// If the types of source and result array are the same and they are not
// sharing the same buffer, use memmove.
TNode<Word32T> source_el_kind = LoadElementsKind(source);
TNode<Word32T> target_el_kind = LoadElementsKind(result_array);
GotoIfNot(Word32Equal(source_el_kind, target_el_kind), &call_c);
TNode<Object> target_buffer =
LoadObjectField(result_array, JSTypedArray::kBufferOffset);
Branch(WordEqual(receiver_buffer, target_buffer), &call_c, &call_memmove);
BIND(&call_memmove);
{
GotoIfForceSlowPath(&call_c);
TNode<IntPtrT> target_data_ptr =
UncheckedCast<IntPtrT>(LoadDataPtr(result_array));
TNode<IntPtrT> source_data_ptr =
UncheckedCast<IntPtrT>(LoadDataPtr(source));
TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
TNode<IntPtrT> source_start_bytes =
IntPtrMul(SmiToIntPtr(start_index), source_el_size);
TNode<IntPtrT> source_start =
IntPtrAdd(source_data_ptr, source_start_bytes);
TNode<IntPtrT> count_bytes = IntPtrMul(SmiToIntPtr(count), source_el_size);
#ifdef DEBUG
TNode<UintPtrT> target_byte_length =
LoadJSArrayBufferViewByteLength(result_array);
CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
target_byte_length));
TNode<UintPtrT> source_byte_length =
LoadJSArrayBufferViewByteLength(source);
TNode<UintPtrT> source_size_in_bytes =
UintPtrSub(source_byte_length, Unsigned(source_start_bytes));
CSA_ASSERT(this, UintPtrLessThanOrEqual(Unsigned(count_bytes),
source_size_in_bytes));
#endif // DEBUG
CallCMemmove(target_data_ptr, source_start, count_bytes);
args.PopAndReturn(result_array);
}
BIND(&call_c);
{
GotoIf(Word32NotEqual(IsBigInt64ElementsKind(source_el_kind),
IsBigInt64ElementsKind(target_el_kind)),
&if_bigint_mixed_types);
CallCCopyTypedArrayElementsSlice(
source, result_array, SmiToIntPtr(start_index), SmiToIntPtr(end_index));
args.PopAndReturn(result_array);
}
BIND(&if_bigint_mixed_types);
ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
}
// ES #sec-get-%typedarray%.prototype-@@tostringtag
TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
@ -1289,8 +1161,10 @@ TF_BUILTIN(TypedArrayPrototypeFilter, TypedArrayBuiltinsAssembler) {
TNode<Smi> captured = LoadFastJSArrayLength(values_array);
// 10. Let A be ? TypedArraySpeciesCreate(O, captured).
TypedArrayCreatetypedarrayBuiltinsFromDSLAssembler typedarray_asm(state());
TNode<JSTypedArray> result_array =
TypedArraySpeciesCreateByLength(context, source, captured, method_name);
typedarray_asm.TypedArraySpeciesCreateByLength(context, method_name,
source, captured);
// 11. Let n be 0.
// 12. For each element e of kept, do

View File

@ -24,10 +24,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<JSTypedArray> exemplar,
TArgs... args);
TNode<JSTypedArray> TypedArraySpeciesCreateByLength(
TNode<Context> context, TNode<JSTypedArray> exemplar, TNode<Smi> len,
const char* method_name);
void GenerateTypedArrayPrototypeIterationMethod(TNode<Context> context,
TNode<Object> receiver,
const char* method_name,
@ -52,7 +48,7 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<BoolT> IsMockArrayBufferAllocatorFlag();
TNode<UintPtrT> CalculateExternalPointer(TNode<UintPtrT> backing_store,
TNode<UintPtrT> byte_offset);
Node* LoadDataPtr(Node* typed_array);
TNode<RawPtrT> LoadDataPtr(TNode<JSTypedArray> typed_array);
// Returns true if kind is either UINT8_ELEMENTS or UINT8_CLAMPED_ELEMENTS.
TNode<Word32T> IsUint8ElementsKind(TNode<Word32T> kind);
@ -95,8 +91,8 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<JSTypedArray> target, TNode<IntPtrT> offset,
Label* call_runtime, Label* if_source_too_large);
void CallCMemmove(TNode<IntPtrT> dest_ptr, TNode<IntPtrT> src_ptr,
TNode<IntPtrT> byte_length);
void CallCMemmove(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length);
void CallCMemcpy(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length);

View File

@ -370,4 +370,19 @@ namespace typed_array_createtypedarray {
return typed_array::ValidateTypedArray(context, newObj, methodName);
}
}
transitioning macro TypedArraySpeciesCreateByLength(implicit context:
Context)(
methodName: constexpr string, exemplar: JSTypedArray,
length: Smi): JSTypedArray {
assert(Is<PositiveSmi>(length));
const numArgs: constexpr int31 = 1;
const typedArray: JSTypedArray = TypedArraySpeciesCreate(
methodName, numArgs, exemplar, length, Undefined, Undefined);
if (typedArray.length < length) deferred {
ThrowTypeError(kTypedArrayTooShort);
}
return typedArray;
}
}

View File

@ -0,0 +1,107 @@
// Copyright 2019 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.
#include 'src/builtins/builtins-typed-array-gen.h'
namespace typed_array_slice {
const kBuiltinName: constexpr string = '%TypedArray%.prototype.slice';
extern macro TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsSlice(
JSTypedArray, JSTypedArray, intptr, intptr): void;
macro FastCopy(
src: typed_array::AttachedJSTypedArray, dest: JSTypedArray, k: intptr,
count: PositiveSmi) labels IfSlow {
GotoIfForceSlowPath() otherwise IfSlow;
const srcKind: ElementsKind = src.elements_kind;
const destInfo = typed_array::GetTypedArrayElementsInfo(dest);
// dest could be a different type from src or share the same buffer
// with the src because of custom species constructor. If the types
// of src and result array are the same and they are not sharing the
// same buffer, use memmove.
if (srcKind != destInfo.kind) goto IfSlow;
if (BitcastTaggedToWord(dest.buffer) == BitcastTaggedToWord(src.buffer)) {
goto IfSlow;
}
const countBytes: uintptr =
destInfo.CalculateByteLength(count) otherwise unreachable;
const startOffset: uintptr =
destInfo.CalculateByteLength(Convert<PositiveSmi>(k))
otherwise unreachable;
const srcPtr: RawPtr = src.data_ptr + Convert<intptr>(startOffset);
assert(countBytes <= dest.byte_length);
assert(countBytes <= src.byte_length - startOffset);
typed_array::CallCMemmove(dest.data_ptr, srcPtr, countBytes);
}
macro SlowCopy(implicit context: Context)(
src: JSTypedArray, dest: JSTypedArray, k: intptr, final: intptr) {
if (typed_array::IsBigInt64ElementsKind(src.elements_kind) !=
typed_array::IsBigInt64ElementsKind(dest.elements_kind))
deferred {
ThrowTypeError(kBigIntMixedTypes);
}
CallCCopyTypedArrayElementsSlice(src, dest, k, final);
}
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice
transitioning javascript builtin TypedArrayPrototypeSlice(
context: Context, receiver: Object, ...arguments): Object {
// arguments[0] = start
// arguments[1] = end
// 1. Let O be the this value.
// 2. Perform ? ValidateTypedArray(O).
const src: JSTypedArray =
typed_array::ValidateTypedArray(context, receiver, kBuiltinName);
// 3. Let len be O.[[ArrayLength]].
const len = Convert<intptr>(src.length);
// 4. Let relativeStart be ? ToInteger(start).
// 5. If relativeStart < 0, let k be max((len + relativeStart), 0);
// else let k be min(relativeStart, len).
const start = arguments[0];
const k: intptr =
start != Undefined ? ConvertToRelativeIndex(start, len) : 0;
// 6. If end is undefined, let relativeEnd be len;
// else let relativeEnd be ? ToInteger(end).
// 7. If relativeEnd < 0, let final be max((len + relativeEnd), 0);
// else let final be min(relativeEnd, len).
const end = arguments[1];
const final: intptr =
end != Undefined ? ConvertToRelativeIndex(end, len) : len;
// 8. Let count be max(final - k, 0).
const count = Convert<PositiveSmi>(IntPtrMax(final - k, 0));
// 9. Let A be ? TypedArraySpeciesCreate(O, « count »).
const dest: JSTypedArray =
typed_array_createtypedarray::TypedArraySpeciesCreateByLength(
kBuiltinName, src, count);
if (count > 0) {
try {
const srcAttached = typed_array::EnsureAttached(src)
otherwise IfDetached;
FastCopy(srcAttached, dest, k, count) otherwise IfSlow;
}
label IfDetached deferred {
ThrowTypeError(kDetachedOperation, kBuiltinName);
}
label IfSlow deferred {
SlowCopy(src, dest, k, final);
}
}
return dest;
}
}

View File

@ -43,12 +43,16 @@ namespace typed_array {
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::CallCMemmove(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::CallCMemset(
RawPtr, intptr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::GetBuffer(
implicit context: Context)(JSTypedArray): JSArrayBuffer;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
JSTypedArray): TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
ElementsKind): bool;
extern macro LoadFixedTypedArrayElementAsTagged(
RawPtr, Smi, constexpr ElementsKind, constexpr ParameterMode): Object;
extern macro StoreFixedTypedArrayElementFromTagged(