[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}
This commit is contained in:
peterwmwong 2019-02-26 22:42:39 -06:00 committed by Commit Bot
parent 5758788c92
commit 19291bfc58
7 changed files with 125 additions and 130 deletions

View File

@ -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") {

View File

@ -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;

View File

@ -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 */ \

View File

@ -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);

View File

@ -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);
}
}
}

View 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(
context, 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(context, 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);
}
}

View File

@ -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(