Commit f2227a2b authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Port TypedArray ConstructByArrayLike to Torque

This is part of an effort to improve the performance of TA#subarray.

Bug: v8:7161
Change-Id: I6f4b0f01e498d48e0fce11fbf7dcd7a0ad1ae748
Reviewed-on: https://chromium-review.googlesource.com/c/1425002
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58988}
parent c5154eea
......@@ -279,6 +279,8 @@ const kNotIterable: constexpr MessageTemplate
const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
const kTypedArrayMaxByteLength:
constexpr uintptr generates 'FixedTypedArrayBase::kMaxByteLength';
const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger';
const kStringMaxLength: constexpr int31 generates 'String::kMaxLength';
const kFixedArrayMaxLength:
......@@ -368,6 +370,10 @@ extern macro ToInteger_Inline(
Context, Object, constexpr ToIntegerTruncationMode): Number;
extern macro ToLength_Inline(Context, Object): Number;
extern macro ToNumber_Inline(Context, Object): Number;
extern macro ToSmiIndex(implicit context: Context)(Object): PositiveSmi
labels IfRangeError;
extern macro ToSmiLength(implicit context: Context)(Object): PositiveSmi
labels IfRangeError;
extern macro ToString_Inline(Context, Object): String;
extern transitioning macro GetProperty(implicit context: Context)(
Object, Object): Object;
......@@ -385,6 +391,8 @@ extern transitioning macro HasProperty_Inline(implicit context: Context)(
extern macro ThrowRangeError(Context, constexpr MessageTemplate): never;
extern macro ThrowRangeError(Context, constexpr MessageTemplate, Object): never;
extern macro ThrowTypeError(Context, constexpr MessageTemplate): never;
extern macro ThrowTypeError(
Context, constexpr MessageTemplate, constexpr string): never;
extern macro ThrowTypeError(Context, constexpr MessageTemplate, Object): never;
extern macro ThrowTypeError(
Context, constexpr MessageTemplate, Object, Object, Object): never;
......@@ -576,6 +584,7 @@ extern operator '>>>' macro ConstexprUintPtrShr(
extern macro SmiMax(Smi, Smi): Smi;
extern macro SmiMin(Smi, Smi): Smi;
extern macro SmiMul(Smi, Smi): Number;
extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
extern operator '!' macro Word32BinaryNot(bool): bool;
......
......@@ -104,7 +104,7 @@ Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32(
// The |number_index| output parameter is used only for architectures that
// don't currently have a TF implementation and forward to runtime functions
// instead; they expect the value has already been coerced to an integer.
*number_index = ToSmiIndex(CAST(tagged), CAST(context), &range_error);
*number_index = ToSmiIndex(CAST(context), CAST(tagged), &range_error);
var_result.Bind(SmiToInt32(*number_index));
Goto(&done);
......
......@@ -391,7 +391,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
BIND(&length_defined);
{
TNode<Smi> new_length = ToSmiIndex(length, context, &invalid_length);
TNode<Smi> new_length = ToSmiIndex(context, length, &invalid_length);
ThrowIfArrayBufferIsDetached(context, buffer, "Construct");
new_byte_length.Bind(SmiMul(new_length, element_size));
// Reading the byte length must come after the ToIndex operation, which
......@@ -412,7 +412,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
TNode<Object> raw_length = CallBuiltin(
Builtins::kDivide, context, new_byte_length.value(), element_size);
// Force the result into a Smi, or throw a range error if it doesn't fit.
TNode<Smi> new_length = ToSmiIndex(raw_length, context, &invalid_length);
TNode<Smi> new_length = ToSmiIndex(context, raw_length, &invalid_length);
CallBuiltin(Builtins::kTypedArrayInitializeWithBuffer, context, holder,
new_length, buffer, element_size, offset.value());
......@@ -498,8 +498,10 @@ void TypedArrayBuiltinsAssembler::ConstructByTypedArray(
BIND(&construct);
{
ConstructByArrayLike(context, holder, typed_array, source_length.value(),
element_size, buffer_constructor.value());
TypedArrayBuiltinsFromDSLAssembler(this->state())
.ConstructByArrayLike(context, holder, typed_array,
source_length.value(), element_size,
buffer_constructor.value());
Goto(&done);
}
......@@ -536,75 +538,6 @@ TNode<BoolT> TypedArrayBuiltinsAssembler::ByteLengthIsValid(
return is_valid.value();
}
void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
TNode<Context> context, TNode<JSTypedArray> holder,
TNode<HeapObject> array_like, TNode<Object> initial_length,
TNode<Smi> element_size, TNode<JSReceiver> buffer_constructor) {
Label invalid_length(this, Label::kDeferred), fill(this), fast_copy(this),
detached_check(this), done(this);
// The caller has looked up length on array_like, which is observable.
TNode<Smi> length = ToSmiLength(initial_length, context, &invalid_length);
Node* initialize = FalseConstant();
CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
element_size, initialize, buffer_constructor);
GotoIf(IsJSTypedArray(array_like), &detached_check);
Goto(&fill);
BIND(&detached_check);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array_like),
"Construct");
Goto(&fill);
BIND(&fill);
GotoIf(SmiEqual(length, SmiConstant(0)), &done);
TNode<Int32T> holder_kind = LoadElementsKind(holder);
TNode<Int32T> source_kind = LoadElementsKind(array_like);
GotoIf(Word32Equal(holder_kind, source_kind), &fast_copy);
// Copy using the elements accessor.
CallRuntime(Runtime::kTypedArrayCopyElements, context, holder, array_like,
length);
Goto(&done);
BIND(&fast_copy);
{
Node* holder_data_ptr = LoadDataPtr(holder);
Node* source_data_ptr = LoadDataPtr(array_like);
// Calculate the byte length. We shouldn't be trying to copy if the typed
// array was detached.
CSA_ASSERT(this, SmiNotEqual(length, SmiConstant(0)));
CSA_ASSERT(this, Word32Equal(IsDetachedBuffer(LoadObjectField(
array_like, JSTypedArray::kBufferOffset)),
Int32Constant(0)));
TNode<Number> byte_length = SmiMul(length, element_size);
CSA_ASSERT(this, ByteLengthIsValid(byte_length));
TNode<UintPtrT> byte_length_intptr =
ChangeNonnegativeNumberToUintPtr(byte_length);
CSA_ASSERT(this, UintPtrLessThanOrEqual(
byte_length_intptr,
IntPtrConstant(FixedTypedArrayBase::kMaxByteLength)));
Node* memcpy = ExternalConstant(ExternalReference::libc_memcpy_function());
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
MachineType::Pointer(), MachineType::UintPtr(), memcpy,
holder_data_ptr, source_data_ptr, byte_length_intptr);
Goto(&done);
}
BIND(&invalid_length);
{
ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
initial_length);
}
BIND(&done);
}
void TypedArrayBuiltinsAssembler::ConstructByIterable(
TNode<Context> context, TNode<JSTypedArray> holder,
TNode<JSReceiver> iterable, TNode<JSReceiver> iterator_fn,
......@@ -619,8 +552,9 @@ void TypedArrayBuiltinsAssembler::ConstructByIterable(
TNode<JSFunction> default_constructor = CAST(LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
ConstructByArrayLike(context, holder, array_like, initial_length,
element_size, default_constructor);
TypedArrayBuiltinsFromDSLAssembler(this->state())
.ConstructByArrayLike(context, holder, array_like, initial_length,
element_size, default_constructor);
}
TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
......@@ -708,8 +642,9 @@ TF_BUILTIN(CreateTypedArray, TypedArrayBuiltinsAssembler) {
TNode<JSFunction> default_constructor = CAST(LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
ConstructByArrayLike(context, result, array_like, initial_length,
element_size, default_constructor);
TypedArrayBuiltinsFromDSLAssembler(this->state())
.ConstructByArrayLike(context, result, array_like, initial_length,
element_size, default_constructor);
Goto(&return_result);
}
......@@ -1114,6 +1049,16 @@ void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
dest_ptr, src_ptr, byte_length);
}
void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length) {
TNode<ExternalReference> memcpy =
ExternalConstant(ExternalReference::libc_memcpy_function());
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
MachineType::Pointer(), MachineType::UintPtr(), memcpy,
dest_ptr, src_ptr, byte_length);
}
void TypedArrayBuiltinsAssembler::
CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
TNode<JSArray> source,
......@@ -1759,7 +1704,7 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
// 10. Let len be ? ToLength(? Get(arrayLike, "length")).
TNode<Object> raw_length =
GetProperty(context, final_source.value(), LengthStringConstant());
final_length = ToSmiLength(raw_length, context, &if_length_not_smi);
final_length = ToSmiLength(context, raw_length, &if_length_not_smi);
Goto(&create_typed_array);
BIND(&if_length_not_smi);
......
......@@ -38,11 +38,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
void ConstructByTypedArray(TNode<Context> context, TNode<JSTypedArray> holder,
TNode<JSTypedArray> typed_array,
TNode<Smi> element_size);
void ConstructByArrayLike(TNode<Context> context, TNode<JSTypedArray> holder,
TNode<HeapObject> array_like,
TNode<Object> initial_length,
TNode<Smi> element_size,
TNode<JSReceiver> buffer_constructor);
void ConstructByIterable(TNode<Context> context, TNode<JSTypedArray> holder,
TNode<JSReceiver> iterable,
TNode<JSReceiver> iterator_fn,
......@@ -107,6 +102,9 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
void CallCMemmove(TNode<IntPtrT> dest_ptr, TNode<IntPtrT> src_ptr,
TNode<IntPtrT> byte_length);
void CallCMemcpy(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
TNode<UintPtrT> byte_length);
void CallCCopyFastNumberJSArrayElementsToTypedArray(
TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
TNode<IntPtrT> source_length, TNode<IntPtrT> offset);
......
......@@ -6,6 +6,13 @@ namespace typed_array {
extern builtin TypedArrayInitialize(implicit context: Context)(
JSTypedArray, PositiveSmi, PositiveSmi, Boolean, JSReceiver): void;
extern macro TypedArrayBuiltinsAssembler::ByteLengthIsValid(Number): bool;
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
void;
// 22.2.4.2 TypedArray ( length )
// ES #sec-typedarray-length
macro ConstructByLength(implicit context: Context)(
......@@ -26,4 +33,41 @@ namespace typed_array {
typedArray, positiveLength, positiveElementSize, initialize,
defaultConstructor);
}
// 22.2.4.4 TypedArray ( object )
// ES #sec-typedarray-object
macro ConstructByArrayLike(implicit context: Context)(
typedArray: JSTypedArray, arrayLike: HeapObject, initialLength: Object,
elementSize: Smi, bufferConstructor: JSReceiver): void {
const positiveElementSize: PositiveSmi =
Cast<PositiveSmi>(elementSize) otherwise unreachable;
// The caller has looked up length on arrayLike, which is observable.
const length: PositiveSmi = ToSmiLength(initialLength)
otherwise ThrowRangeError(context, kInvalidTypedArrayLength, initialLength);
const initialize: Boolean = False;
TypedArrayInitialize(
typedArray, length, positiveElementSize, initialize, bufferConstructor);
try {
const src: JSTypedArray = Cast<JSTypedArray>(arrayLike) otherwise IfSlow;
if (IsDetachedBuffer(src.buffer)) {
ThrowTypeError(context, kDetachedOperation, 'Construct');
} else if (src.elements_kind != typedArray.elements_kind) {
goto IfSlow;
} else if (length > 0) {
const byteLength: Number = SmiMul(length, elementSize);
assert(ByteLengthIsValid(byteLength));
CallCMemcpy(
typedArray.data_ptr, src.data_ptr, Convert<uintptr>(byteLength));
}
}
label IfSlow deferred {
if (length > 0) {
TypedArrayCopyElements(context, typedArray, arrayLike, length);
}
}
}
}
......@@ -7905,8 +7905,8 @@ TNode<JSReceiver> CodeStubAssembler::ToObject_Inline(TNode<Context> context,
return result.value();
}
TNode<Smi> CodeStubAssembler::ToSmiIndex(TNode<Object> input,
TNode<Context> context,
TNode<Smi> CodeStubAssembler::ToSmiIndex(TNode<Context> context,
TNode<Object> input,
Label* range_error) {
TVARIABLE(Smi, result);
Label check_undefined(this), return_zero(this), defined(this),
......@@ -7937,8 +7937,8 @@ TNode<Smi> CodeStubAssembler::ToSmiIndex(TNode<Object> input,
return result.value();
}
TNode<Smi> CodeStubAssembler::ToSmiLength(TNode<Object> input,
TNode<Context> context,
TNode<Smi> CodeStubAssembler::ToSmiLength(TNode<Context> context,
TNode<Object> input,
Label* range_error) {
TVARIABLE(Smi, result);
Label to_integer(this), negative_check(this),
......
......@@ -2239,11 +2239,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
};
// ES6 7.1.17 ToIndex, but jumps to range_error if the result is not a Smi.
TNode<Smi> ToSmiIndex(TNode<Object> input, TNode<Context> context,
TNode<Smi> ToSmiIndex(TNode<Context> context, TNode<Object> input,
Label* range_error);
// ES6 7.1.15 ToLength, but jumps to range_error if the result is not a Smi.
TNode<Smi> ToSmiLength(TNode<Object> input, TNode<Context> context,
TNode<Smi> ToSmiLength(TNode<Context> context, TNode<Object> input,
Label* range_error);
// ES6 7.1.15 ToLength, but with inlined fast path.
......
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