blob: d8fc788dfbb66f2b2eea470c46af7fa356c02708 [file] [log] [blame]
// 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 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;
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):
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
JSTypedArray): TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind):
extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(ElementsKind):
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>();
extern macro
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 {
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 {
context, typedArray, index, value, KindForArrayType<T>())
otherwise IfDetached;
} label IfDetached {
return kStoreFailureArrayDetached;
return kStoreSucceded;