blob: 37784eeb144733c49854964fa8c4e04cc477c9dd [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 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 Float16Elements extends ElementsKind;
type Float32Elements extends ElementsKind;
type Float64Elements extends ElementsKind;
type Uint8ClampedElements extends ElementsKind;
type BigUint64Elements extends ElementsKind;
type BigInt64Elements extends ElementsKind;
type RabGsabUint8Elements extends ElementsKind;
@export
struct TypedArrayElementsInfo {
// Calculates the number of bytes required for specified number of elements.
macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid {
const maxArrayLength = ArrayBufferMaxByteLength() >>> 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 {
return byteLength >>> this.sizeLog2;
}
// 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::ValidateTypedArrayAndGetLength(
Context, JSAny, constexpr string): uintptr;
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 TypedArrayBuiltinsAssembler::CallCRelaxedMemcpy(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::CallCRelaxedMemmove(
RawPtr, RawPtr, 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): void;
extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
Context, JSTypedArray, uintptr, JSAny,
constexpr ElementsKind): void labels IfDetached;
extern macro LoadJSTypedArrayLengthAndCheckDetached(JSTypedArray): uintptr
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 kStoreFailureArrayDetachedOrOutOfBounds: 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): void {
const storefn: StoreNumericFn = this.storeNumericFn;
const result = storefn(context, array, index, value);
dcheck(result == kStoreSucceded);
}
macro StoreJSAnyInBounds(
context: Context, array: JSTypedArray, index: uintptr,
value: JSAny): void {
const storefn: StoreJSAnyFn = this.storeJSAnyFn;
const result = storefn(context, array, index, value);
check(result == kStoreSucceded);
}
macro StoreJSAny(
context: Context, array: JSTypedArray, index: uintptr,
value: JSAny): void {
const storefn: StoreJSAnyFn = this.storeJSAnyFn;
const result = storefn(context, array, index, value);
// ES#sec-typedarray-set
//
// A [[Set]] on a TypedArray with a detached or out-of-bounds
// underlying ArrayBuffer is a no-op.
dcheck(
result == kStoreSucceded ||
result == kStoreFailureArrayDetachedOrOutOfBounds);
}
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(elementsKindParam: ElementsKind):
TypedArrayAccessor {
let elementsKind = elementsKindParam;
if (IsElementsKindGreaterThanOrEqual(
elementsKind, kFirstRabGsabFixedTypedArrayElementsKind)) {
elementsKind = %RawDownCast<ElementsKind>(
elementsKind - kFirstRabGsabFixedTypedArrayElementsKind +
kFirstFixedTypedArrayElementsKind);
}
if (IsElementsKindGreaterThan(elementsKind, ElementsKind::UINT32_ELEMENTS)) {
if (elementsKind == ElementsKind::INT32_ELEMENTS) {
return GetTypedArrayAccessor<Int32Elements>();
} else if (elementsKind == ElementsKind::FLOAT16_ELEMENTS) {
return GetTypedArrayAccessor<Float16Elements>();
} 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::SetJSTypedArrayOnHeapDataPtr(
JSTypedArray, ByteArray, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
JSTypedArray, RawPtr, uintptr): void;
extern macro IsJSArrayBufferViewDetachedOrOutOfBounds(JSArrayBufferView):
never labels DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
extern macro IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(
JSArrayBufferView): bool;
// AttachedJSTypedArray guards that the array's buffer is not detached.
transient type AttachedJSTypedArray extends JSTypedArray;
macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray
labels DetachedOrOutOfBounds {
try {
IsJSArrayBufferViewDetachedOrOutOfBounds(array)
otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds;
} label NotDetachedNorOutOfBounds {
return %RawDownCast<AttachedJSTypedArray>(array);
}
}
struct AttachedJSTypedArrayAndLength {
array: AttachedJSTypedArray;
length: uintptr;
}
macro EnsureAttachedAndReadLength(array: JSTypedArray):
AttachedJSTypedArrayAndLength
labels DetachedOrOutOfBounds {
const length = LoadJSTypedArrayLengthAndCheckDetached(array)
otherwise DetachedOrOutOfBounds;
return AttachedJSTypedArrayAndLength{
array: %RawDownCast<AttachedJSTypedArray>(array),
length: length
};
}
struct AttachedJSTypedArrayWitness {
macro GetStable(): JSTypedArray {
return this.stable;
}
macro RecheckIndex(index: uintptr): void labels DetachedOrOutOfBounds {
const length = LoadJSTypedArrayLengthAndCheckDetached(this.stable)
otherwise DetachedOrOutOfBounds;
if (index >= length) {
goto DetachedOrOutOfBounds;
}
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<Float16Elements>(): constexpr ElementsKind {
return ElementsKind::FLOAT16_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 success 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 IfDetachedOrOutOfBounds;
} label IfDetachedOrOutOfBounds {
return kStoreFailureArrayDetachedOrOutOfBounds;
}
return kStoreSucceded;
}
}