Reland "[typedarray] Port TA#subarray and TypedArraySpeciesCreate to Torque"
This is a reland of 19291bfc58
Same as original, but with ThrowTypeError/ThrowRange updated to use an implicit context.
Original change's description:
> [typedarray] Port TA#subarray and TypedArraySpeciesCreate to Torque
>
> Reduces TypedArrayPrototypeSubArray builtin size by 392 bytes:
> - TFJ Builtin, TypedArrayPrototypeSubArray, 2448 -> 2056
>
> Small 3-4% perf increase on JSTests/TypedArrays/SubarrayNoSpecies benchmark
>
> Bug: v8:7161, v8:8906
> Change-Id: Ia2b906a93db7199ca4592c46c40638cca0a33eec
> Reviewed-on: https://chromium-review.googlesource.com/c/1485241
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Reviewed-by: Simon Zünd <szuend@chromium.org>
> Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
> Cr-Commit-Position: refs/heads/master@{#59894}
Bug: v8:7161, v8:8906
Change-Id: Ic3784e2d4db262b1968ba467b7b46b98203f11d4
Reviewed-on: https://chromium-review.googlesource.com/c/1491533
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Cr-Commit-Position: refs/heads/master@{#59901}
This commit is contained in:
parent
88f038705f
commit
1937e2b128
2
BUILD.gn
2
BUILD.gn
@ -923,6 +923,7 @@ torque_files = [
|
||||
"src/builtins/string-startswith.tq",
|
||||
"src/builtins/typed-array.tq",
|
||||
"src/builtins/typed-array-createtypedarray.tq",
|
||||
"src/builtins/typed-array-subarray.tq",
|
||||
"test/torque/test-torque.tq",
|
||||
"third_party/v8/builtins/array-sort.tq",
|
||||
]
|
||||
@ -951,6 +952,7 @@ torque_namespaces = [
|
||||
"test",
|
||||
"typed-array",
|
||||
"typed-array-createtypedarray",
|
||||
"typed-array-subarray",
|
||||
]
|
||||
|
||||
action("run_torque") {
|
||||
|
@ -729,6 +729,9 @@ extern macro SmiMin(Smi, Smi): Smi;
|
||||
extern macro SmiMul(Smi, Smi): Number;
|
||||
extern macro SmiMod(Smi, Smi): Number;
|
||||
|
||||
extern macro IntPtrMax(intptr, intptr): intptr;
|
||||
extern macro IntPtrMin(intptr, intptr): intptr;
|
||||
|
||||
extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
|
||||
extern operator '!' macro Word32BinaryNot(bool): bool;
|
||||
extern operator '!' macro IsFalse(Boolean): bool;
|
||||
@ -1167,6 +1170,10 @@ Convert<intptr, uintptr>(ui: uintptr): intptr {
|
||||
assert(i >= 0);
|
||||
return i;
|
||||
}
|
||||
Convert<PositiveSmi, intptr>(i: intptr): PositiveSmi {
|
||||
assert(IsValidPositiveSmi(i));
|
||||
return %RawDownCast<PositiveSmi>(SmiTag(i));
|
||||
}
|
||||
Convert<int32, Smi>(s: Smi): int32 {
|
||||
return SmiToInt32(s);
|
||||
}
|
||||
@ -1252,6 +1259,8 @@ extern macro IsArraySpeciesProtectorCellInvalid(): bool;
|
||||
extern macro IsTypedArraySpeciesProtectorCellInvalid(): bool;
|
||||
extern macro IsPromiseSpeciesProtectorCellInvalid(): bool;
|
||||
extern macro IsMockArrayBufferAllocatorFlag(): bool;
|
||||
extern macro IsPrototypeTypedArrayPrototype(implicit context: Context)(Map):
|
||||
bool;
|
||||
|
||||
extern operator '.data_ptr' macro TypedArrayBuiltinsAssembler::LoadDataPtr(
|
||||
JSTypedArray): RawPtr;
|
||||
@ -1617,6 +1626,8 @@ extern macro AllocateSeqTwoByteString(implicit context: Context)(uint32):
|
||||
String;
|
||||
extern macro TryIntPtrAdd(intptr, intptr): intptr
|
||||
labels IfOverflow;
|
||||
extern macro ConvertToRelativeIndex(implicit context: Context)(
|
||||
Object, intptr): intptr;
|
||||
|
||||
extern builtin ObjectToString(Context, Object): Object;
|
||||
extern builtin StringRepeat(Context, String, Number): String;
|
||||
|
@ -1159,9 +1159,6 @@ namespace internal {
|
||||
/* ES6 #sec-%typedarray%.prototype.slice */ \
|
||||
TFJ(TypedArrayPrototypeSlice, \
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 %TypedArray%.prototype.subarray */ \
|
||||
TFJ(TypedArrayPrototypeSubArray, \
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 #sec-get-%typedarray%.prototype-@@tostringtag */ \
|
||||
TFJ(TypedArrayPrototypeToStringTag, 0, kReceiver) \
|
||||
/* ES6 %TypedArray%.prototype.every */ \
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/builtins/growable-fixed-array-gen.h"
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/heap/factory-inl.h"
|
||||
#include "torque-generated/builtins-typed-array-createtypedarray-from-dsl-gen.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -304,67 +305,17 @@ TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
|
||||
LoadContextElement(LoadNativeContext(context), context_slot.value()));
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArraySpeciesCreate(
|
||||
const char* method_name, TNode<Context> context,
|
||||
TNode<JSTypedArray> exemplar, TArgs... args) {
|
||||
TVARIABLE(JSTypedArray, var_new_typed_array);
|
||||
Label slow(this, Label::kDeferred), done(this);
|
||||
|
||||
// Let defaultConstructor be the intrinsic object listed in column one of
|
||||
// Table 52 for exemplar.[[TypedArrayName]].
|
||||
TNode<JSFunction> default_constructor =
|
||||
GetDefaultConstructor(context, exemplar);
|
||||
|
||||
TNode<Map> map = LoadMap(exemplar);
|
||||
GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
|
||||
GotoIf(IsTypedArraySpeciesProtectorCellInvalid(), &slow);
|
||||
{
|
||||
const size_t argc = sizeof...(args);
|
||||
static_assert(argc >= 1 && argc <= 3,
|
||||
"TypedArraySpeciesCreate called with unexpected arguments");
|
||||
TNode<Object> arg_list[argc] = {args...};
|
||||
TNode<Object> arg0 = argc < 1 ? UndefinedConstant() : arg_list[0];
|
||||
TNode<Object> arg1 = argc < 2 ? UndefinedConstant() : arg_list[1];
|
||||
TNode<Object> arg2 = argc < 3 ? UndefinedConstant() : arg_list[2];
|
||||
var_new_typed_array = UncheckedCast<JSTypedArray>(
|
||||
CallBuiltin(Builtins::kCreateTypedArray, context, default_constructor,
|
||||
default_constructor, arg0, arg1, arg2));
|
||||
#ifdef DEBUG
|
||||
// It is assumed that the CreateTypedArray builtin does not produce a
|
||||
// typed array that fails ValidateTypedArray.
|
||||
TNode<JSArrayBuffer> buffer =
|
||||
LoadJSArrayBufferViewBuffer(var_new_typed_array.value());
|
||||
CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(buffer)));
|
||||
#endif // DEBUG
|
||||
Goto(&done);
|
||||
}
|
||||
BIND(&slow);
|
||||
{
|
||||
// Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
|
||||
TNode<JSReceiver> constructor =
|
||||
SpeciesConstructor(context, exemplar, default_constructor);
|
||||
|
||||
// Let newTypedArray be ? Construct(constructor, argumentList).
|
||||
TNode<JSReceiver> new_object = Construct(context, constructor, args...);
|
||||
|
||||
// Perform ? ValidateTypedArray(newTypedArray).
|
||||
var_new_typed_array = ValidateTypedArray(context, new_object, method_name);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return var_new_typed_array.value();
|
||||
}
|
||||
|
||||
TNode<JSTypedArray>
|
||||
TypedArrayBuiltinsAssembler::TypedArraySpeciesCreateByLength(
|
||||
TNode<Context> context, TNode<JSTypedArray> exemplar, TNode<Smi> len,
|
||||
const char* method_name) {
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(len));
|
||||
|
||||
TNode<JSTypedArray> new_typed_array =
|
||||
TypedArraySpeciesCreate(method_name, context, exemplar, 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;
|
||||
@ -858,77 +809,6 @@ TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
|
||||
ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
|
||||
}
|
||||
|
||||
// ES %TypedArray%.prototype.subarray
|
||||
TF_BUILTIN(TypedArrayPrototypeSubArray, TypedArrayBuiltinsAssembler) {
|
||||
const char* method_name = "%TypedArray%.prototype.subarray";
|
||||
Label offset_done(this);
|
||||
|
||||
TVARIABLE(Smi, var_begin);
|
||||
TVARIABLE(Smi, var_end);
|
||||
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
CodeStubArguments args(
|
||||
this,
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount)));
|
||||
|
||||
// 1. Let O be the this value.
|
||||
// 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError
|
||||
// exception.
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
ThrowIfNotInstanceType(context, receiver, JS_TYPED_ARRAY_TYPE, method_name);
|
||||
|
||||
TNode<JSTypedArray> source = CAST(receiver);
|
||||
|
||||
// 5. Let buffer be O.[[ViewedArrayBuffer]].
|
||||
TNode<JSArrayBuffer> buffer = GetBuffer(context, source);
|
||||
// 6. Let srcLength be O.[[ArrayLength]].
|
||||
TNode<Smi> source_length = LoadJSTypedArrayLength(source);
|
||||
|
||||
// 7. Let relativeBegin be ? ToInteger(begin).
|
||||
// 8. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin),
|
||||
// 0); else let beginIndex be min(relativeBegin, srcLength).
|
||||
TNode<Object> begin = args.GetOptionalArgumentValue(0, SmiConstant(0));
|
||||
var_begin =
|
||||
SmiTag(ConvertToRelativeIndex(context, begin, SmiUntag(source_length)));
|
||||
|
||||
TNode<Object> end = args.GetOptionalArgumentValue(1, UndefinedConstant());
|
||||
// 9. If end is undefined, let relativeEnd be srcLength;
|
||||
var_end = source_length;
|
||||
GotoIf(IsUndefined(end), &offset_done);
|
||||
|
||||
// else, let relativeEnd be ? ToInteger(end).
|
||||
// 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0);
|
||||
// else let endIndex be min(relativeEnd, srcLength).
|
||||
var_end =
|
||||
SmiTag(ConvertToRelativeIndex(context, end, SmiUntag(source_length)));
|
||||
Goto(&offset_done);
|
||||
|
||||
BIND(&offset_done);
|
||||
|
||||
// 11. Let newLength be max(endIndex - beginIndex, 0).
|
||||
TNode<Smi> new_length =
|
||||
SmiMax(SmiSub(var_end.value(), var_begin.value()), SmiConstant(0));
|
||||
|
||||
// 12. Let constructorName be the String value of O.[[TypedArrayName]].
|
||||
// 13. Let elementSize be the Number value of the Element Size value specified
|
||||
// in Table 52 for constructorName.
|
||||
TNode<Word32T> element_kind = LoadElementsKind(source);
|
||||
TNode<IntPtrT> element_size = GetTypedArrayElementSize(element_kind);
|
||||
|
||||
// 14. Let srcByteOffset be O.[[ByteOffset]].
|
||||
TNode<Number> source_byte_offset =
|
||||
ChangeUintPtrToTagged(LoadJSArrayBufferViewByteOffset(source));
|
||||
|
||||
// 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
|
||||
TNode<Number> offset = SmiMul(var_begin.value(), SmiFromIntPtr(element_size));
|
||||
TNode<Number> begin_byte_offset = NumberAdd(source_byte_offset, offset);
|
||||
|
||||
// 16. Let argumentsList be « buffer, beginByteOffset, newLength ».
|
||||
// 17. Return ? TypedArraySpeciesCreate(O, argumentsList).
|
||||
args.PopAndReturn(TypedArraySpeciesCreate(
|
||||
method_name, context, source, buffer, begin_byte_offset, new_length));
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype-@@tostringtag
|
||||
TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
|
||||
Node* receiver = Parameter(Descriptor::kReceiver);
|
||||
|
@ -14,6 +14,8 @@ namespace typed_array_createtypedarray {
|
||||
implicit context: Context)(JSTypedArray, uintptr): JSArrayBuffer;
|
||||
extern macro TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
|
||||
Map, intptr, Number): FixedTypedArrayBase;
|
||||
extern macro TypedArrayBuiltinsAssembler::GetDefaultConstructor(
|
||||
implicit context: Context)(JSTypedArray): JSFunction;
|
||||
extern macro TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(JSArrayBuffer):
|
||||
bool;
|
||||
extern macro TypedArrayBuiltinsAssembler::SetupTypedArray(
|
||||
@ -279,7 +281,7 @@ namespace typed_array_createtypedarray {
|
||||
// ES #sec-typedarray-constructors
|
||||
transitioning builtin CreateTypedArray(
|
||||
context: Context, target: JSFunction, newTarget: JSReceiver, arg1: Object,
|
||||
arg2: Object, arg3: Object): Object {
|
||||
arg2: Object, arg3: Object): JSTypedArray {
|
||||
assert(IsConstructor(target));
|
||||
// 4. Let O be ? AllocateTypedArray(constructorName, NewTarget,
|
||||
// "%TypedArrayPrototype%").
|
||||
@ -330,4 +332,42 @@ namespace typed_array_createtypedarray {
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
transitioning macro TypedArraySpeciesCreate(implicit context: Context)(
|
||||
methodName: constexpr string, numArgs: constexpr int31,
|
||||
exemplar: JSTypedArray, arg0: Object, arg1: Object,
|
||||
arg2: Object): JSTypedArray {
|
||||
const defaultConstructor = GetDefaultConstructor(exemplar);
|
||||
|
||||
try {
|
||||
if (!IsPrototypeTypedArrayPrototype(exemplar.map)) goto IfSlow;
|
||||
if (IsTypedArraySpeciesProtectorCellInvalid()) goto IfSlow;
|
||||
|
||||
const typedArray = CreateTypedArray(
|
||||
context, defaultConstructor, defaultConstructor, arg0, arg1, arg2);
|
||||
|
||||
// It is assumed that the CreateTypedArray builtin does not produce a
|
||||
// typed array that fails ValidateTypedArray
|
||||
assert(!IsDetachedBuffer(typedArray.buffer));
|
||||
|
||||
return typedArray;
|
||||
}
|
||||
label IfSlow deferred {
|
||||
const constructor =
|
||||
Cast<Constructor>(SpeciesConstructor(exemplar, defaultConstructor))
|
||||
otherwise unreachable;
|
||||
|
||||
// TODO(pwong): Simplify and remove numArgs when varargs are supported in
|
||||
// macros.
|
||||
let newObj: Object = Undefined;
|
||||
if constexpr (numArgs == 1) {
|
||||
newObj = Construct(constructor, arg0);
|
||||
} else {
|
||||
assert(numArgs == 3);
|
||||
newObj = Construct(constructor, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
return typed_array::ValidateTypedArray(context, newObj, methodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
63
src/builtins/typed-array-subarray.tq
Normal file
63
src/builtins/typed-array-subarray.tq
Normal file
@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
|
||||
namespace typed_array_subarray {
|
||||
// ES %TypedArray%.prototype.subarray
|
||||
transitioning javascript builtin TypedArrayPrototypeSubArray(
|
||||
context: Context, receiver: Object, ...arguments): JSTypedArray {
|
||||
const methodName: constexpr string = '%TypedArray%.prototype.subarray';
|
||||
|
||||
// 1. Let O be the this value.
|
||||
// 3. If O does not have a [[TypedArrayName]] internal slot, throw a
|
||||
// TypeError exception.
|
||||
const source = Cast<JSTypedArray>(receiver)
|
||||
otherwise ThrowTypeError(kIncompatibleMethodReceiver, methodName);
|
||||
|
||||
// 5. Let buffer be O.[[ViewedArrayBuffer]].
|
||||
const buffer = typed_array::GetBuffer(source);
|
||||
|
||||
// 6. Let srcLength be O.[[ArrayLength]].
|
||||
const srcLength = Convert<intptr>(source.length);
|
||||
|
||||
// 7. Let relativeBegin be ? ToInteger(begin).
|
||||
// 8. If relativeBegin < 0, let beginIndex be max((srcLength +
|
||||
// relativeBegin), 0); else let beginIndex be min(relativeBegin,
|
||||
// srcLength).
|
||||
const arg0 = arguments[0];
|
||||
const begin: intptr =
|
||||
arg0 != Undefined ? ConvertToRelativeIndex(arg0, srcLength) : 0;
|
||||
|
||||
// 9. If end is undefined, let relativeEnd be srcLength;
|
||||
// else, let relativeEnd be ? ToInteger(end).
|
||||
// 10. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd),
|
||||
// 0); else let endIndex be min(relativeEnd, srcLength).
|
||||
const arg1 = arguments[1];
|
||||
const end: intptr =
|
||||
arg1 != Undefined ? ConvertToRelativeIndex(arg1, srcLength) : srcLength;
|
||||
|
||||
// 11. Let newLength be max(endIndex - beginIndex, 0).
|
||||
const newLength = Convert<PositiveSmi>(IntPtrMax(end - begin, 0));
|
||||
|
||||
// 12. Let constructorName be the String value of O.[[TypedArrayName]].
|
||||
// 13. Let elementSize be the Number value of the Element Size value
|
||||
// specified in Table 52 for constructorName.
|
||||
const elementsInfo = typed_array::GetTypedArrayElementsInfo(source);
|
||||
|
||||
// 14. Let srcByteOffset be O.[[ByteOffset]].
|
||||
const srcByteOffset: uintptr = source.byte_offset;
|
||||
|
||||
// 15. Let beginByteOffset be srcByteOffset + beginIndex × elementSize.
|
||||
const beginByteOffset = srcByteOffset +
|
||||
elementsInfo.CalculateByteLength(Convert<PositiveSmi>(begin))
|
||||
otherwise ThrowRangeError(kInvalidArrayBufferLength);
|
||||
|
||||
// 16. Let argumentsList be « buffer, beginByteOffset, newLength ».
|
||||
const beginByteOffsetNum = Convert<Number>(beginByteOffset);
|
||||
|
||||
// 17. Return ? TypedArraySpeciesCreate(O, argumentsList).
|
||||
const numArgs: constexpr int31 = 3;
|
||||
return typed_array_createtypedarray::TypedArraySpeciesCreate(
|
||||
methodName, numArgs, source, buffer, beginByteOffsetNum, newLength);
|
||||
}
|
||||
}
|
@ -45,6 +45,8 @@ namespace typed_array {
|
||||
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 LoadFixedTypedArrayElementAsTagged(
|
||||
|
Loading…
Reference in New Issue
Block a user