summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/typed-array-createtypedarray.tq
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/typed-array-createtypedarray.tq')
-rw-r--r--deps/v8/src/builtins/typed-array-createtypedarray.tq371
1 files changed, 343 insertions, 28 deletions
diff --git a/deps/v8/src/builtins/typed-array-createtypedarray.tq b/deps/v8/src/builtins/typed-array-createtypedarray.tq
index 64d9930815..04630dc295 100644
--- a/deps/v8/src/builtins/typed-array-createtypedarray.tq
+++ b/deps/v8/src/builtins/typed-array-createtypedarray.tq
@@ -2,23 +2,92 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-namespace typed_array {
- extern builtin TypedArrayInitialize(implicit context: Context)(
- JSTypedArray, PositiveSmi, PositiveSmi, Boolean, JSReceiver): void;
+#include 'src/builtins/builtins-constructor-gen.h'
- extern macro TypedArrayBuiltinsAssembler::ByteLengthIsValid(Number): bool;
- extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
- RawPtr, RawPtr, uintptr): void;
+namespace typed_array_createtypedarray {
+ extern builtin IterableToListMayPreserveHoles(Context, Object, Callable):
+ JSArray;
+ extern macro ConstructorBuiltinsAssembler::EmitFastNewObject(
+ implicit context: Context)(JSFunction, JSReceiver): JSTypedArray;
+ extern macro TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
+ 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(
+ JSTypedArray, Smi, uintptr, uintptr): void;
+
+ extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)(
+ Map, String): never;
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
void;
+ macro CalculateTotalElementsByteSize(byteLength: intptr): intptr {
+ return (kFixedTypedArrayBaseHeaderSize + kObjectAlignmentMask +
+ byteLength) &
+ ~kObjectAlignmentMask;
+ }
+
+ transitioning macro TypedArrayInitialize(implicit context: Context)(
+ initialize: constexpr bool, typedArray: JSTypedArray, length: PositiveSmi,
+ elementsInfo: typed_array::TypedArrayElementsInfo,
+ bufferConstructor: JSReceiver): uintptr {
+ const byteLength = elementsInfo.CalculateByteLength(length)
+ otherwise ThrowRangeError(kInvalidArrayBufferLength);
+ const byteLengthNum = Convert<Number>(byteLength);
+ const defaultConstructor = GetArrayBufferFunction();
+
+ try {
+ if (bufferConstructor != defaultConstructor) {
+ goto AttachOffHeapBuffer(ConstructWithTarget(
+ defaultConstructor, bufferConstructor, byteLengthNum));
+ }
+
+ if (byteLength > V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP) goto AllocateOffHeap;
+
+ AllocateEmptyOnHeapBuffer(typedArray, byteLength);
+
+ const totalSize =
+ CalculateTotalElementsByteSize(Convert<intptr>(byteLength));
+ const elements =
+ AllocateOnHeapElements(elementsInfo.map, totalSize, length);
+ typedArray.elements = elements;
+
+ if constexpr (initialize) {
+ const backingStore = LoadFixedTypedArrayOnHeapBackingStore(elements);
+ typed_array::CallCMemset(backingStore, 0, byteLength);
+ }
+ }
+ label AllocateOffHeap {
+ if constexpr (initialize) {
+ goto AttachOffHeapBuffer(Construct(defaultConstructor, byteLengthNum));
+ } else {
+ goto AttachOffHeapBuffer(Call(
+ context, GetArrayBufferNoInitFunction(), Undefined, byteLengthNum));
+ }
+ }
+ label AttachOffHeapBuffer(bufferObj: Object) {
+ const buffer = Cast<JSArrayBuffer>(bufferObj) otherwise unreachable;
+ const byteOffset: uintptr = 0;
+ typedArray.AttachOffHeapBuffer(
+ buffer, elementsInfo.map, length, byteOffset);
+ }
+
+ const byteOffset: uintptr = 0;
+ SetupTypedArray(typedArray, length, byteOffset, byteLength);
+
+ return byteLength;
+ }
+
// 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;
+ transitioning macro ConstructByLength(implicit context: Context)(
+ typedArray: JSTypedArray, length: Object,
+ elementsInfo: typed_array::TypedArrayElementsInfo): void {
const convertedLength: Number =
ToInteger_Inline(context, length, kTruncateMinusZero);
// The maximum length of a TypedArray is MaxSmi().
@@ -26,42 +95,39 @@ namespace typed_array {
// representation (which uses Smis).
// TODO(7881): support larger-than-smi typed array lengths
const positiveLength: PositiveSmi = Cast<PositiveSmi>(convertedLength)
- otherwise ThrowRangeError(context, kInvalidTypedArrayLength, length);
- const defaultConstructor: JSFunction = GetArrayBufferFunction();
- const initialize: Boolean = True;
+ otherwise ThrowRangeError(kInvalidTypedArrayLength, length);
+ const defaultConstructor: Constructor = GetArrayBufferFunction();
+ const initialize: constexpr bool = true;
TypedArrayInitialize(
- typedArray, positiveLength, positiveElementSize, initialize,
+ initialize, typedArray, positiveLength, elementsInfo,
defaultConstructor);
}
// 22.2.4.4 TypedArray ( object )
// ES #sec-typedarray-object
- macro ConstructByArrayLike(implicit context: Context)(
+ transitioning 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: typed_array::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);
+ otherwise ThrowRangeError(kInvalidTypedArrayLength, initialLength);
+ const initialize: constexpr bool = false;
+ const byteLength = TypedArrayInitialize(
+ initialize, typedArray, length, elementsInfo, bufferConstructor);
try {
const src: JSTypedArray = Cast<JSTypedArray>(arrayLike) otherwise IfSlow;
if (IsDetachedBuffer(src.buffer)) {
- ThrowTypeError(context, kDetachedOperation, 'Construct');
+ ThrowTypeError(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);
- assert(ByteLengthIsValid(byteLength));
- CallCMemcpy(
- typedArray.data_ptr, src.data_ptr, Convert<uintptr>(byteLength));
+ assert(byteLength <= kTypedArrayMaxByteLength);
+ typed_array::CallCMemcpy(typedArray.data_ptr, src.data_ptr, byteLength);
}
}
label IfSlow deferred {
@@ -70,4 +136,253 @@ namespace typed_array {
}
}
}
+
+ // 22.2.4.4 TypedArray ( object )
+ // ES #sec-typedarray-object
+ transitioning macro ConstructByIterable(implicit context: Context)(
+ typedArray: JSTypedArray, iterable: JSReceiver, iteratorFn: Callable,
+ elementsInfo: typed_array::TypedArrayElementsInfo): never
+ labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ const array: JSArray =
+ IterableToListMayPreserveHoles(context, iterable, iteratorFn);
+ goto IfConstructByArrayLike(array, array.length, GetArrayBufferFunction());
+ }
+
+ // 22.2.4.3 TypedArray ( typedArray )
+ // ES #sec-typedarray-typedarray
+ transitioning macro ConstructByTypedArray(implicit context: Context)(
+ typedArray: JSTypedArray, srcTypedArray: JSTypedArray,
+ elementsInfo: typed_array::TypedArrayElementsInfo): never
+ labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ let bufferConstructor: JSReceiver = GetArrayBufferFunction();
+ const srcBuffer: JSArrayBuffer = srcTypedArray.buffer;
+ // TODO(petermarshall): Throw on detached typedArray.
+ let length: Smi = IsDetachedBuffer(srcBuffer) ? 0 : srcTypedArray.length;
+
+ // The spec requires that constructing a typed array using a SAB-backed
+ // typed array use the ArrayBuffer constructor, not the species constructor.
+ // See https://tc39.github.io/ecma262/#sec-typedarray-typedarray.
+ if (!IsSharedArrayBuffer(srcBuffer)) {
+ bufferConstructor = SpeciesConstructor(srcBuffer, bufferConstructor);
+ // TODO(petermarshall): Throw on detached typedArray.
+ if (IsDetachedBuffer(srcBuffer)) length = 0;
+ }
+ goto IfConstructByArrayLike(srcTypedArray, length, bufferConstructor);
+ }
+
+ // 22.2.4.5 TypedArray ( buffer, byteOffset, length )
+ // ES #sec-typedarray-buffer-byteoffset-length
+ macro ConstructByArrayBuffer(implicit context: Context)(
+ typedArray: JSTypedArray, buffer: JSArrayBuffer, byteOffset: Object,
+ length: Object, elementsInfo: typed_array::TypedArrayElementsInfo): void {
+ try {
+ let offset: uintptr = 0;
+ if (byteOffset != Undefined) {
+ // 6. Let offset be ? ToIndex(byteOffset).
+ offset = TryNumberToUintPtr(
+ ToInteger_Inline(context, byteOffset, kTruncateMinusZero))
+ otherwise goto IfInvalidOffset;
+
+ // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
+ if (elementsInfo.IsUnaligned(offset)) {
+ goto IfInvalidAlignment('start offset');
+ }
+ }
+
+ let newLength: PositiveSmi = 0;
+ let newByteLength: uintptr;
+ // 8. If length is present and length is not undefined, then
+ if (length != Undefined) {
+ // a. Let newLength be ? ToIndex(length).
+ newLength = ToSmiIndex(length) otherwise IfInvalidLength;
+ }
+
+ // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
+ if (IsDetachedBuffer(buffer)) {
+ ThrowTypeError(kDetachedOperation, 'Construct');
+ }
+
+ // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
+ const bufferByteLength: uintptr = buffer.byte_length;
+
+ // 11. If length is either not present or undefined, then
+ if (length == Undefined) {
+ // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError
+ // exception.
+ if (elementsInfo.IsUnaligned(bufferByteLength)) {
+ goto IfInvalidAlignment('byte length');
+ }
+
+ // b. Let newByteLength be bufferByteLength - offset.
+ // c. If newByteLength < 0, throw a RangeError exception.
+ if (bufferByteLength < offset) goto IfInvalidOffset;
+
+ // Spec step 16 length calculated here to avoid recalculating the length
+ // in the step 12 branch.
+ newByteLength = bufferByteLength - offset;
+ newLength = elementsInfo.CalculateLength(newByteLength)
+ otherwise IfInvalidOffset;
+
+ // 12. Else,
+ } else {
+ // a. Let newByteLength be newLength × elementSize.
+ newByteLength = elementsInfo.CalculateByteLength(newLength)
+ otherwise IfInvalidByteLength;
+
+ // b. If offset + newByteLength > bufferByteLength, throw a RangeError
+ // exception.
+ if ((bufferByteLength < newByteLength) ||
+ (offset > bufferByteLength - newByteLength))
+ goto IfInvalidLength;
+ }
+
+ SetupTypedArray(typedArray, newLength, offset, newByteLength);
+ typedArray.AttachOffHeapBuffer(
+ buffer, elementsInfo.map, newLength, offset);
+ }
+ label IfInvalidAlignment(problemString: String) deferred {
+ ThrowInvalidTypedArrayAlignment(typedArray.map, problemString);
+ }
+ label IfInvalidByteLength deferred {
+ ThrowRangeError(kInvalidArrayBufferLength);
+ }
+ label IfInvalidLength deferred {
+ ThrowRangeError(kInvalidTypedArrayLength, length);
+ }
+ label IfInvalidOffset deferred {
+ ThrowRangeError(kInvalidOffset, byteOffset);
+ }
+ }
+
+ transitioning macro ConstructByJSReceiver(implicit context: Context)(
+ array: JSTypedArray, obj: JSReceiver,
+ elementsInfo: typed_array::TypedArrayElementsInfo): never
+ labels IfConstructByArrayLike(HeapObject, Object, JSReceiver) {
+ try {
+ const iteratorMethod: Object =
+ GetIteratorMethod(obj) otherwise IfIteratorUndefined;
+ const iteratorFn: Callable = Cast<Callable>(iteratorMethod)
+ otherwise ThrowTypeError(kIteratorSymbolNonCallable);
+ ConstructByIterable(array, obj, iteratorFn, elementsInfo)
+ otherwise IfConstructByArrayLike;
+ }
+ label IfIteratorUndefined {
+ const lengthObj: Object = GetProperty(obj, kLengthString);
+ const length: Smi = ToSmiLength(lengthObj)
+ otherwise goto IfInvalidLength(lengthObj);
+ goto IfConstructByArrayLike(obj, length, GetArrayBufferFunction());
+ }
+ label IfInvalidLength(length: Object) {
+ ThrowRangeError(kInvalidTypedArrayLength, length);
+ }
+ }
+
+ // 22.2.4 The TypedArray Constructors
+ // ES #sec-typedarray-constructors
+ transitioning builtin CreateTypedArray(
+ context: Context, target: JSFunction, newTarget: JSReceiver, arg1: Object,
+ arg2: Object, arg3: Object): JSTypedArray {
+ assert(IsConstructor(target));
+ // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget,
+ // "%TypedArrayPrototype%").
+ const array: JSTypedArray = EmitFastNewObject(target, newTarget);
+ // We need to set the byte_offset / byte_length to some sane values
+ // to keep the heap verifier happy.
+ // TODO(bmeurer): Fix this initialization to not use EmitFastNewObject,
+ // which causes the problem, since it puts Undefined into all slots of
+ // the object even though that doesn't make any sense for these fields.
+ array.byte_offset = 0;
+ array.byte_length = 0;
+
+ // 5. Let elementSize be the Number value of the Element Size value in Table
+ // 56 for constructorName.
+ const elementsInfo: typed_array::TypedArrayElementsInfo =
+ typed_array::GetTypedArrayElementsInfo(array);
+
+ try {
+ typeswitch (arg1) {
+ case (length: Smi): {
+ goto IfConstructByLength(length);
+ }
+ case (buffer: JSArrayBuffer): {
+ ConstructByArrayBuffer(array, buffer, arg2, arg3, elementsInfo);
+ }
+ case (typedArray: JSTypedArray): {
+ ConstructByTypedArray(array, typedArray, elementsInfo)
+ otherwise IfConstructByArrayLike;
+ }
+ case (obj: JSReceiver): {
+ ConstructByJSReceiver(array, obj, elementsInfo)
+ otherwise IfConstructByArrayLike;
+ }
+ // The first argument was a number or fell through and is treated as
+ // a number. https://tc39.github.io/ecma262/#sec-typedarray-length
+ case (lengthObj: HeapObject): {
+ goto IfConstructByLength(lengthObj);
+ }
+ }
+ }
+ label IfConstructByLength(length: Object) {
+ ConstructByLength(array, length, elementsInfo);
+ }
+ label IfConstructByArrayLike(
+ arrayLike: HeapObject, length: Object, bufferConstructor: JSReceiver) {
+ ConstructByArrayLike(
+ array, arrayLike, length, elementsInfo, bufferConstructor);
+ }
+ 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);
+ }
+ }
+
+ 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;
+ }
}