| // Copyright 2018 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. |
| |
| #include 'src/builtins/builtins-typed-array-gen.h' |
| |
| namespace typed_array { |
| // Naming convention from elements.cc. We have a similar intent but implement |
| // fastpaths using generics instead of using a class hierarchy for elements |
| // kinds specific implementations. |
| type Uint8Elements extends ElementsKind; |
| type Int8Elements extends ElementsKind; |
| type Uint16Elements extends ElementsKind; |
| type Int16Elements extends ElementsKind; |
| type Uint32Elements extends ElementsKind; |
| type Int32Elements extends ElementsKind; |
| type Float32Elements extends ElementsKind; |
| type Float64Elements extends ElementsKind; |
| type Uint8ClampedElements extends ElementsKind; |
| type BigUint64Elements extends ElementsKind; |
| type BigInt64Elements extends ElementsKind; |
| |
| @export |
| struct TypedArrayElementsInfo { |
| // Calculates the number of bytes required for specified number of elements. |
| macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid { |
| if (length > kTypedArrayMaxLength) goto IfInvalid; |
| const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2; |
| if (length > maxArrayLength) goto IfInvalid; |
| const byteLength = length << this.sizeLog2; |
| return byteLength; |
| } |
| |
| // Calculates the maximum number of elements supported by a specified number |
| // of bytes. |
| macro CalculateLength(byteLength: uintptr): uintptr labels IfInvalid { |
| const length = byteLength >>> this.sizeLog2; |
| if (length > kTypedArrayMaxLength) goto IfInvalid; |
| return length; |
| } |
| |
| // Determines if `bytes` (byte offset or length) cannot be evenly divided by |
| // element size. |
| macro IsUnaligned(bytes: uintptr): bool { |
| // Exploits the fact the element size is a power of 2. Determining whether |
| // there is remainder (not aligned) can be achieved efficiently with bit |
| // masking. Shift is safe as sizeLog2 can be 3 at most (see |
| // ElementsKindToShiftSize). |
| return (bytes & ((1 << this.sizeLog2) - 1)) != 0; |
| } |
| |
| sizeLog2: uintptr; |
| kind: ElementsKind; |
| } |
| extern runtime TypedArrayCopyElements( |
| Context, JSTypedArray, Object, Number): void; |
| extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray( |
| Context, JSAny, constexpr string): JSTypedArray; |
| |
| extern macro TypedArrayBuiltinsAssembler::CallCMemcpy( |
| RawPtr, RawPtr, uintptr): void; |
| extern macro TypedArrayBuiltinsAssembler::CallCMemmove( |
| RawPtr, RawPtr, uintptr): void; |
| extern macro TypedArrayBuiltinsAssembler::CallCMemset( |
| RawPtr, intptr, uintptr): void; |
| extern macro GetTypedArrayBuffer(implicit context: Context)(JSTypedArray): |
| JSArrayBuffer; |
| extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo( |
| JSTypedArray): TypedArrayElementsInfo; |
| extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map): |
| TypedArrayElementsInfo; |
| extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind): |
| bool; |
| extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(ElementsKind): |
| bool; |
| extern macro LoadFixedTypedArrayElementAsTagged( |
| RawPtr, uintptr, constexpr ElementsKind): Numeric; |
| extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( |
| Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind); |
| extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged( |
| Context, JSTypedArray, uintptr, JSAny, constexpr ElementsKind) |
| labels IfDetached; |
| |
| type LoadNumericFn = builtin(JSTypedArray, uintptr) => Numeric; |
| type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi; |
| type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi; |
| |
| // The result codes returned by StoreNumericFn and StoreJSAnyFn builtins. |
| const kStoreSucceded: Smi = 0; |
| const kStoreFailureArrayDetached: Smi = 1; |
| |
| struct TypedArrayAccessor { |
| macro LoadNumeric(array: JSTypedArray, index: uintptr): Numeric { |
| const loadfn: LoadNumericFn = this.loadNumericFn; |
| return loadfn(array, index); |
| } |
| |
| macro StoreNumeric( |
| context: Context, array: JSTypedArray, index: uintptr, value: Numeric) { |
| const storefn: StoreNumericFn = this.storeNumericFn; |
| const result = storefn(context, array, index, value); |
| assert(result == kStoreSucceded); |
| } |
| |
| macro StoreJSAny( |
| context: Context, array: JSTypedArray, index: uintptr, value: JSAny) |
| labels IfDetached { |
| const storefn: StoreJSAnyFn = this.storeJSAnyFn; |
| const result = storefn(context, array, index, value); |
| if (result == kStoreFailureArrayDetached) { |
| goto IfDetached; |
| } |
| assert(result == kStoreSucceded); |
| } |
| |
| loadNumericFn: LoadNumericFn; |
| storeNumericFn: StoreNumericFn; |
| storeJSAnyFn: StoreJSAnyFn; |
| } |
| |
| macro GetTypedArrayAccessor<T : type extends ElementsKind>(): |
| TypedArrayAccessor { |
| const loadNumericFn = LoadTypedElement<T>; |
| const storeNumericFn = StoreTypedElementNumeric<T>; |
| const storeJSAnyFn = StoreTypedElementJSAny<T>; |
| return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn}; |
| } |
| |
| macro GetTypedArrayAccessor(elementsKind: ElementsKind): TypedArrayAccessor { |
| if (IsElementsKindGreaterThan(elementsKind, ElementsKind::UINT32_ELEMENTS)) { |
| if (elementsKind == ElementsKind::INT32_ELEMENTS) { |
| return GetTypedArrayAccessor<Int32Elements>(); |
| } else if (elementsKind == ElementsKind::FLOAT32_ELEMENTS) { |
| return GetTypedArrayAccessor<Float32Elements>(); |
| } else if (elementsKind == ElementsKind::FLOAT64_ELEMENTS) { |
| return GetTypedArrayAccessor<Float64Elements>(); |
| } else if (elementsKind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { |
| return GetTypedArrayAccessor<Uint8ClampedElements>(); |
| } else if (elementsKind == ElementsKind::BIGUINT64_ELEMENTS) { |
| return GetTypedArrayAccessor<BigUint64Elements>(); |
| } else if (elementsKind == ElementsKind::BIGINT64_ELEMENTS) { |
| return GetTypedArrayAccessor<BigInt64Elements>(); |
| } |
| } else { |
| if (elementsKind == ElementsKind::UINT8_ELEMENTS) { |
| return GetTypedArrayAccessor<Uint8Elements>(); |
| } else if (elementsKind == ElementsKind::INT8_ELEMENTS) { |
| return GetTypedArrayAccessor<Int8Elements>(); |
| } else if (elementsKind == ElementsKind::UINT16_ELEMENTS) { |
| return GetTypedArrayAccessor<Uint16Elements>(); |
| } else if (elementsKind == ElementsKind::INT16_ELEMENTS) { |
| return GetTypedArrayAccessor<Int16Elements>(); |
| } else if (elementsKind == ElementsKind::UINT32_ELEMENTS) { |
| return GetTypedArrayAccessor<Uint32Elements>(); |
| } |
| } |
| unreachable; |
| } |
| |
| extern macro |
| TypedArrayBuiltinsAssembler::AllocateJSTypedArrayExternalPointerEntry( |
| JSTypedArray): void; |
| |
| extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( |
| JSTypedArray, ByteArray, uintptr): void; |
| extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( |
| JSTypedArray, RawPtr, uintptr): void; |
| |
| // AttachedJSTypedArray guards that the array's buffer is not detached. |
| transient type AttachedJSTypedArray extends JSTypedArray; |
| |
| macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray |
| labels Detached { |
| if (IsDetachedBuffer(array.buffer)) goto Detached; |
| return %RawDownCast<AttachedJSTypedArray>(array); |
| } |
| |
| struct AttachedJSTypedArrayWitness { |
| macro Get(): AttachedJSTypedArray { |
| return this.unstable; |
| } |
| |
| macro GetStable(): JSTypedArray { |
| return this.stable; |
| } |
| |
| macro Recheck() labels Detached { |
| if (IsDetachedBuffer(this.stable.buffer)) goto Detached; |
| this.unstable = %RawDownCast<AttachedJSTypedArray>(this.stable); |
| } |
| |
| macro Load(implicit context: Context)(k: uintptr): JSAny { |
| const lf: LoadNumericFn = this.loadfn; |
| return lf(this.unstable, k); |
| } |
| |
| stable: JSTypedArray; |
| unstable: AttachedJSTypedArray; |
| loadfn: LoadNumericFn; |
| } |
| |
| macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray): |
| AttachedJSTypedArrayWitness { |
| const kind = array.elements_kind; |
| const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind); |
| return AttachedJSTypedArrayWitness{ |
| stable: array, |
| unstable: array, |
| loadfn: accessor.loadNumericFn |
| }; |
| } |
| |
| macro KindForArrayType<T : type extends ElementsKind>(): constexpr ElementsKind; |
| KindForArrayType<Uint8Elements>(): constexpr ElementsKind { |
| return ElementsKind::UINT8_ELEMENTS; |
| } |
| KindForArrayType<Int8Elements>(): constexpr ElementsKind { |
| return ElementsKind::INT8_ELEMENTS; |
| } |
| KindForArrayType<Uint16Elements>(): constexpr ElementsKind { |
| return ElementsKind::UINT16_ELEMENTS; |
| } |
| KindForArrayType<Int16Elements>(): constexpr ElementsKind { |
| return ElementsKind::INT16_ELEMENTS; |
| } |
| KindForArrayType<Uint32Elements>(): constexpr ElementsKind { |
| return ElementsKind::UINT32_ELEMENTS; |
| } |
| KindForArrayType<Int32Elements>(): constexpr ElementsKind { |
| return ElementsKind::INT32_ELEMENTS; |
| } |
| KindForArrayType<Float32Elements>(): constexpr ElementsKind { |
| return ElementsKind::FLOAT32_ELEMENTS; |
| } |
| KindForArrayType<Float64Elements>(): constexpr ElementsKind { |
| return ElementsKind::FLOAT64_ELEMENTS; |
| } |
| KindForArrayType<Uint8ClampedElements>(): constexpr ElementsKind { |
| return ElementsKind::UINT8_CLAMPED_ELEMENTS; |
| } |
| KindForArrayType<BigUint64Elements>(): constexpr ElementsKind { |
| return ElementsKind::BIGUINT64_ELEMENTS; |
| } |
| KindForArrayType<BigInt64Elements>(): constexpr ElementsKind { |
| return ElementsKind::BIGINT64_ELEMENTS; |
| } |
| |
| builtin LoadTypedElement<T : type extends ElementsKind>( |
| array: JSTypedArray, index: uintptr): Numeric { |
| return LoadFixedTypedArrayElementAsTagged( |
| array.data_ptr, index, KindForArrayType<T>()); |
| } |
| |
| builtin StoreTypedElementNumeric<T : type extends ElementsKind>( |
| context: Context, typedArray: JSTypedArray, index: uintptr, |
| value: Numeric): Smi { |
| StoreJSTypedArrayElementFromNumeric( |
| context, typedArray, index, value, KindForArrayType<T>()); |
| return kStoreSucceded; |
| } |
| |
| // Returns True on sucess or False if the typedArrays was detached. |
| builtin StoreTypedElementJSAny<T : type extends ElementsKind>( |
| context: Context, typedArray: JSTypedArray, index: uintptr, |
| value: JSAny): Smi { |
| try { |
| StoreJSTypedArrayElementFromTagged( |
| context, typedArray, index, value, KindForArrayType<T>()) |
| otherwise IfDetached; |
| } label IfDetached { |
| return kStoreFailureArrayDetached; |
| } |
| return kStoreSucceded; |
| } |
| } |