[builtins] Port TypedArray TypedArrayInitializeWithBuffer to Torque

Two small changes were done as part of the port:
- Changes TypedArrayInitializeWithBuffer from a TFS builtin to a macro.
  It was only called from ConstructByArrayBuffer and this removes the
  overhead of the TFS call.
- Introduces a GetTypedArrayElementsInfo that retrieves both the element
  size and map. Instead of generating the elements kind switch code (
  DispatchTypedArrayByElementsKind) twice, just generate once at the
  beginning of CreateTypedArray.

This reduces overall builtins size by 364 bytes (Mac x64.release)
  - Before
    1364 - TypedArrayInitializeWithBuffer
    6468 - CreateTypedArray
  - After
    7468 - CreateTypedArray

This also improves performance of TypedArray JSPerf benchmarks
(SubarrayNoSpecies, ConstructByArrayBuffer) by 5-8%.

Bug: v8:7161
Change-Id: I68eed2ea4db103f44ad9751229c29fba9bc9d24d
Reviewed-on: https://chromium-review.googlesource.com/c/1437822
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59135}
This commit is contained in:
peterwmwong 2019-01-28 09:13:02 -06:00 committed by Commit Bot
parent 7215f6d632
commit 8e13ddc680
5 changed files with 80 additions and 56 deletions

View File

@ -1157,8 +1157,6 @@ namespace internal {
/* TypedArray */ \
TFS(TypedArrayInitialize, kHolder, kLength, kElementSize, kInitialize, \
kBufferConstructor) \
TFS(TypedArrayInitializeWithBuffer, kHolder, kLength, kBuffer, kElementSize, \
kByteOffset) \
/* ES #sec-typedarray-constructors */ \
TFJ(TypedArrayBaseConstructor, 0, kReceiver) \
TFJ(GenericConstructorLazyDeoptContinuation, 1, kReceiver, kResult) \

View File

@ -10,7 +10,6 @@
#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-from-dsl-gen.h"
namespace v8 {
namespace internal {
@ -106,24 +105,6 @@ void TypedArrayBuiltinsAssembler::AttachBuffer(TNode<JSTypedArray> holder,
StoreObjectField(holder, JSObject::kElementsOffset, elements);
}
TF_BUILTIN(TypedArrayInitializeWithBuffer, TypedArrayBuiltinsAssembler) {
TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
TNode<JSArrayBuffer> buffer = CAST(Parameter(Descriptor::kBuffer));
TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
TNode<Number> byte_offset = CAST(Parameter(Descriptor::kByteOffset));
TNode<Map> fixed_typed_map = LoadMapForType(holder);
// SmiMul returns a heap number in case of Smi overflow.
TNode<Number> byte_length = SmiMul(length, element_size);
SetupTypedArray(holder, length, ChangeNonnegativeNumberToUintPtr(byte_offset),
ChangeNonnegativeNumberToUintPtr(byte_length));
AttachBuffer(holder, buffer, fixed_typed_map, length, byte_offset);
Return(UndefinedConstant());
}
TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
@ -463,6 +444,28 @@ TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
return element_size.value();
}
TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo
TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
TNode<JSTypedArray> typed_array) {
TNode<Int32T> elements_kind = LoadElementsKind(typed_array);
TVARIABLE(Smi, var_element_size);
TVARIABLE(Map, var_map);
ReadOnlyRoots roots(isolate());
DispatchTypedArrayByElementsKind(
elements_kind,
[&](ElementsKind kind, int size, int typed_array_fun_index) {
DCHECK_GT(size, 0);
var_element_size = SmiConstant(size);
Handle<Map> map(roots.MapForFixedTypedArray(kind), isolate());
var_map = HeapConstant(map);
});
return TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo{
var_element_size.value(), var_map.value(), elements_kind};
}
TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
TNode<Context> context, TNode<JSTypedArray> exemplar) {
TVARIABLE(IntPtrT, context_slot);

View File

@ -6,6 +6,7 @@
#define V8_BUILTINS_BUILTINS_TYPED_ARRAY_GEN_H_
#include "src/code-stub-assembler.h"
#include "torque-generated/builtins-typed-array-from-dsl-gen.h"
namespace v8 {
namespace internal {
@ -52,6 +53,10 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
// Returns the byte size of an element for a TypedArray elements kind.
TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
// Returns information (byte size and map) about a TypedArray's elements.
TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo
GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array);
TNode<JSArrayBuffer> LoadTypedArrayBuffer(TNode<JSTypedArray> typed_array) {
return LoadObjectField<JSArrayBuffer>(typed_array,
JSTypedArray::kBufferOffset);

View File

@ -9,30 +9,41 @@ namespace typed_array {
JSArray;
extern builtin TypedArrayInitialize(implicit context: Context)(
JSTypedArray, PositiveSmi, PositiveSmi, Boolean, JSReceiver): void;
extern builtin TypedArrayInitializeWithBuffer(implicit context: Context)(
JSTypedArray, PositiveSmi, JSArrayBuffer, PositiveSmi, Number): void;
extern macro ConstructorBuiltinsAssembler::EmitFastNewObject(
implicit context: Context)(JSFunction, JSReceiver): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::ByteLengthIsValid(Number): bool;
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
ElementsKind): intptr;
extern macro TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(JSArrayBuffer):
bool;
extern macro TypedArrayBuiltinsAssembler::SetupTypedArray(
JSTypedArray, PositiveSmi, uintptr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::AttachBuffer(
JSTypedArray, JSArrayBuffer, Map, PositiveSmi, Number): void;
extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)(
Map, String): never;
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
void;
macro TypedArrayInitializeWithBuffer(
typedArray: JSTypedArray, length: PositiveSmi, buffer: JSArrayBuffer,
elementsInfo: TypedArrayElementsInfo, byteOffset: Number) {
const byteLength: Number = SmiMul(length, elementsInfo.size);
SetupTypedArray(
typedArray, length, Convert<uintptr>(byteOffset),
Convert<uintptr>(byteLength));
AttachBuffer(typedArray, buffer, elementsInfo.map, length, byteOffset);
}
// 22.2.4.2 TypedArray ( length )
// ES #sec-typedarray-length
macro ConstructByLength(implicit context: Context)(
typedArray: JSTypedArray, length: Object, elementSize: Smi): void {
const positiveElementSize: PositiveSmi =
Cast<PositiveSmi>(elementSize) otherwise unreachable;
typedArray: JSTypedArray, length: Object,
elementsInfo: TypedArrayElementsInfo): void {
const convertedLength: Number =
ToInteger_Inline(context, length, kTruncateMinusZero);
// The maximum length of a TypedArray is MaxSmi().
@ -44,7 +55,7 @@ namespace typed_array {
const defaultConstructor: JSFunction = GetArrayBufferFunction();
const initialize: Boolean = True;
TypedArrayInitialize(
typedArray, positiveLength, positiveElementSize, initialize,
typedArray, positiveLength, elementsInfo.size, initialize,
defaultConstructor);
}
@ -52,15 +63,14 @@ namespace typed_array {
// 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;
elementsInfo: TypedArrayElementsInfo,
bufferConstructor: JSReceiver): void {
// 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);
typedArray, length, elementsInfo.size, initialize, bufferConstructor);
try {
const src: JSTypedArray = Cast<JSTypedArray>(arrayLike) otherwise IfSlow;
@ -68,11 +78,11 @@ namespace typed_array {
if (IsDetachedBuffer(src.buffer)) {
ThrowTypeError(context, kDetachedOperation, 'Construct');
} else if (src.elements_kind != typedArray.elements_kind) {
} else if (src.elements_kind != elementsInfo.kind) {
goto IfSlow;
} else if (length > 0) {
const byteLength: Number = SmiMul(length, elementSize);
const byteLength: Number = SmiMul(length, elementsInfo.size);
assert(ByteLengthIsValid(byteLength));
CallCMemcpy(
typedArray.data_ptr, src.data_ptr, Convert<uintptr>(byteLength));
@ -89,18 +99,19 @@ namespace typed_array {
// ES #sec-typedarray-object
macro ConstructByIterable(implicit context: Context)(
typedArray: JSTypedArray, iterable: JSReceiver, iteratorFn: Callable,
elementSize: Smi): void {
elementsInfo: TypedArrayElementsInfo): void {
const array: JSArray =
IterableToListMayPreserveHoles(context, iterable, iteratorFn);
ConstructByArrayLike(
typedArray, array, array.length, elementSize, GetArrayBufferFunction());
typedArray, array, array.length, elementsInfo,
GetArrayBufferFunction());
}
// 22.2.4.3 TypedArray ( typedArray )
// ES #sec-typedarray-typedarray
macro ConstructByTypedArray(implicit context: Context)(
typedArray: JSTypedArray, srcTypedArray: JSTypedArray,
elementSize: Smi): void {
elementsInfo: TypedArrayElementsInfo): void {
let bufferConstructor: JSReceiver = GetArrayBufferFunction();
const srcBuffer: JSArrayBuffer = srcTypedArray.buffer;
// TODO(petermarshall): Throw on detached typedArray.
@ -115,7 +126,7 @@ namespace typed_array {
if (IsDetachedBuffer(srcBuffer)) length = 0;
}
ConstructByArrayLike(
typedArray, srcTypedArray, length, elementSize, bufferConstructor);
typedArray, srcTypedArray, length, elementsInfo, bufferConstructor);
}
// Determines if `bytes` (byte offset or length) cannot be evenly divded by
@ -133,9 +144,7 @@ namespace typed_array {
// ES #sec-typedarray-buffer-byteoffset-length
macro ConstructByArrayBuffer(implicit context: Context)(
typedArray: JSTypedArray, buffer: JSArrayBuffer, byteOffset: Object,
length: Object, elementSize: Smi): void {
const positiveElementSize: PositiveSmi =
Cast<PositiveSmi>(elementSize) otherwise unreachable;
length: Object, elementsInfo: TypedArrayElementsInfo): void {
try {
let offset: Number = FromConstexpr<Smi>(0);
if (byteOffset != Undefined) {
@ -144,7 +153,7 @@ namespace typed_array {
if (offset < 0) goto IfInvalidOffset;
// 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
if (IsUnaligned(offset, positiveElementSize)) {
if (IsUnaligned(offset, elementsInfo.size)) {
goto IfInvalidAlignment('start offset');
}
}
@ -168,7 +177,7 @@ namespace typed_array {
if (length == Undefined) {
// a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError
// exception.
if (IsUnaligned(bufferByteLength, positiveElementSize)) {
if (IsUnaligned(bufferByteLength, elementsInfo.size)) {
goto IfInvalidAlignment('byte length');
}
@ -179,13 +188,13 @@ namespace typed_array {
// Spec step 16 length calculated here to avoid recalculating the length
// in the step 12 branch.
newLength = ToSmiIndex(
Divide((Subtract(bufferByteLength, offset)), positiveElementSize))
Divide((Subtract(bufferByteLength, offset)), elementsInfo.size))
otherwise IfInvalidLength;
// 12. Else,
} else {
// a. Let newByteLength be newLength × elementSize.
const newByteLength: Number = SmiMul(newLength, positiveElementSize);
const newByteLength: Number = SmiMul(newLength, elementsInfo.size);
// b. If offset + newByteLength > bufferByteLength, throw a RangeError
// exception.
@ -196,7 +205,7 @@ namespace typed_array {
}
TypedArrayInitializeWithBuffer(
typedArray, newLength, buffer, positiveElementSize, offset);
typedArray, newLength, buffer, elementsInfo, offset);
}
label IfInvalidAlignment(problemString: String) deferred {
ThrowInvalidTypedArrayAlignment(typedArray.map, problemString);
@ -210,20 +219,21 @@ namespace typed_array {
}
transitioning macro ConstructByJSReceiver(implicit context: Context)(
array: JSTypedArray, obj: JSReceiver, elementSize: Smi) {
array: JSTypedArray, obj: JSReceiver,
elementsInfo: TypedArrayElementsInfo) {
try {
const iteratorMethod: Object =
GetIteratorMethod(obj) otherwise IfIteratorUndefined;
const iteratorFn: Callable = Cast<Callable>(iteratorMethod)
otherwise ThrowTypeError(context, kIteratorSymbolNonCallable);
ConstructByIterable(array, obj, iteratorFn, elementSize);
ConstructByIterable(array, obj, iteratorFn, elementsInfo);
}
label IfIteratorUndefined {
const lengthObj: Object = GetProperty(obj, kLengthString);
const length: Smi = ToSmiLength(lengthObj)
otherwise goto IfInvalidLength(lengthObj);
ConstructByArrayLike(
array, obj, length, elementSize, GetArrayBufferFunction());
array, obj, length, elementsInfo, GetArrayBufferFunction());
}
label IfInvalidLength(length: Object) {
ThrowRangeError(context, kInvalidTypedArrayLength, length);
@ -249,8 +259,8 @@ namespace typed_array {
// 5. Let elementSize be the Number value of the Element Size value in Table
// 56 for constructorName.
const elementSize: Smi =
Convert<Smi>(GetTypedArrayElementSize(array.elements_kind));
const elementsInfo: TypedArrayElementsInfo =
GetTypedArrayElementsInfo(array);
try {
typeswitch (arg1) {
@ -258,13 +268,13 @@ namespace typed_array {
goto IfConstructByLength(length);
}
case (buffer: JSArrayBuffer): {
ConstructByArrayBuffer(array, buffer, arg2, arg3, elementSize);
ConstructByArrayBuffer(array, buffer, arg2, arg3, elementsInfo);
}
case (typedArray: JSTypedArray): {
ConstructByTypedArray(array, typedArray, elementSize);
ConstructByTypedArray(array, typedArray, elementsInfo);
}
case (obj: JSReceiver): {
ConstructByJSReceiver(array, obj, elementSize);
ConstructByJSReceiver(array, obj, elementsInfo);
}
// The first argument was a number or fell through and is treated as
// a number. https://tc39.github.io/ecma262/#sec-typedarray-length
@ -274,7 +284,7 @@ namespace typed_array {
}
}
label IfConstructByLength(length: Object) {
ConstructByLength(array, length, elementSize);
ConstructByLength(array, length, elementsInfo);
}
return array;
}

View File

@ -5,10 +5,18 @@
#include 'src/builtins/builtins-typed-array-gen.h'
namespace typed_array {
struct TypedArrayElementsInfo {
size: PositiveSmi;
map: Map;
kind: ElementsKind;
}
extern runtime TypedArraySortFast(Context, Object): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray(
Context, Object, constexpr string): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
JSTypedArray): TypedArrayElementsInfo;
extern macro LoadFixedTypedArrayElementAsTagged(
RawPtr, Smi, constexpr ElementsKind, constexpr ParameterMode): Object;
extern macro StoreFixedTypedArrayElementFromTagged(