1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include 'src/builtins/builtins-typed-array-gen.h' 6 7namespace typed_array { 8// Naming convention from elements.cc. We have a similar intent but implement 9// fastpaths using generics instead of using a class hierarchy for elements 10// kinds specific implementations. 11type Uint8Elements extends ElementsKind; 12type Int8Elements extends ElementsKind; 13type Uint16Elements extends ElementsKind; 14type Int16Elements extends ElementsKind; 15type Uint32Elements extends ElementsKind; 16type Int32Elements extends ElementsKind; 17type Float32Elements extends ElementsKind; 18type Float64Elements extends ElementsKind; 19type Uint8ClampedElements extends ElementsKind; 20type BigUint64Elements extends ElementsKind; 21type BigInt64Elements extends ElementsKind; 22type RabGsabUint8Elements extends ElementsKind; 23 24@export 25struct TypedArrayElementsInfo { 26 // Calculates the number of bytes required for specified number of elements. 27 macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid { 28 if (length > kTypedArrayMaxLength) goto IfInvalid; 29 const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2; 30 if (length > maxArrayLength) goto IfInvalid; 31 const byteLength = length << this.sizeLog2; 32 return byteLength; 33 } 34 35 // Calculates the maximum number of elements supported by a specified number 36 // of bytes. 37 macro CalculateLength(byteLength: uintptr): uintptr labels IfInvalid { 38 const length = byteLength >>> this.sizeLog2; 39 if (length > kTypedArrayMaxLength) goto IfInvalid; 40 return length; 41 } 42 43 // Determines if `bytes` (byte offset or length) cannot be evenly divided by 44 // element size. 45 macro IsUnaligned(bytes: uintptr): bool { 46 // Exploits the fact the element size is a power of 2. Determining whether 47 // there is remainder (not aligned) can be achieved efficiently with bit 48 // masking. Shift is safe as sizeLog2 can be 3 at most (see 49 // ElementsKindToShiftSize). 50 return (bytes & ((1 << this.sizeLog2) - 1)) != 0; 51 } 52 53 sizeLog2: uintptr; 54 kind: ElementsKind; 55} 56extern runtime TypedArrayCopyElements( 57 Context, JSTypedArray, Object, Number): void; 58extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray( 59 Context, JSAny, constexpr string): JSTypedArray; 60extern macro TypedArrayBuiltinsAssembler::ValidateTypedArrayAndGetLength( 61 Context, JSAny, constexpr string): uintptr; 62 63extern macro TypedArrayBuiltinsAssembler::CallCMemcpy( 64 RawPtr, RawPtr, uintptr): void; 65extern macro TypedArrayBuiltinsAssembler::CallCMemmove( 66 RawPtr, RawPtr, uintptr): void; 67extern macro TypedArrayBuiltinsAssembler::CallCMemset( 68 RawPtr, intptr, uintptr): void; 69extern macro TypedArrayBuiltinsAssembler::CallCRelaxedMemcpy( 70 RawPtr, RawPtr, uintptr): void; 71extern macro TypedArrayBuiltinsAssembler::CallCRelaxedMemmove( 72 RawPtr, RawPtr, uintptr): void; 73extern macro GetTypedArrayBuffer(implicit context: Context)(JSTypedArray): 74 JSArrayBuffer; 75extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo( 76 JSTypedArray): TypedArrayElementsInfo; 77extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map): 78 TypedArrayElementsInfo; 79extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind): 80 bool; 81extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(ElementsKind): 82 bool; 83extern macro LoadFixedTypedArrayElementAsTagged( 84 RawPtr, uintptr, constexpr ElementsKind): Numeric; 85extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( 86 Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind): void; 87extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged( 88 Context, JSTypedArray, uintptr, JSAny, 89 constexpr ElementsKind): void labels IfDetached; 90 91extern macro LoadJSTypedArrayLengthAndCheckDetached(JSTypedArray): uintptr 92 labels IfDetached; 93 94type LoadNumericFn = builtin(JSTypedArray, uintptr) => Numeric; 95type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi; 96type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi; 97 98// The result codes returned by StoreNumericFn and StoreJSAnyFn builtins. 99const kStoreSucceded: Smi = 0; 100const kStoreFailureArrayDetached: Smi = 1; 101 102struct TypedArrayAccessor { 103 macro LoadNumeric(array: JSTypedArray, index: uintptr): Numeric { 104 const loadfn: LoadNumericFn = this.loadNumericFn; 105 return loadfn(array, index); 106 } 107 108 macro StoreNumeric( 109 context: Context, array: JSTypedArray, index: uintptr, 110 value: Numeric): void { 111 const storefn: StoreNumericFn = this.storeNumericFn; 112 const result = storefn(context, array, index, value); 113 dcheck(result == kStoreSucceded); 114 } 115 116 macro StoreJSAny( 117 context: Context, array: JSTypedArray, index: uintptr, 118 value: JSAny): void labels IfDetached { 119 const storefn: StoreJSAnyFn = this.storeJSAnyFn; 120 const result = storefn(context, array, index, value); 121 if (result == kStoreFailureArrayDetached) { 122 goto IfDetached; 123 } 124 dcheck(result == kStoreSucceded); 125 } 126 127 loadNumericFn: LoadNumericFn; 128 storeNumericFn: StoreNumericFn; 129 storeJSAnyFn: StoreJSAnyFn; 130} 131 132macro GetTypedArrayAccessor<T : type extends ElementsKind>(): 133 TypedArrayAccessor { 134 const loadNumericFn = LoadTypedElement<T>; 135 const storeNumericFn = StoreTypedElementNumeric<T>; 136 const storeJSAnyFn = StoreTypedElementJSAny<T>; 137 return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn}; 138} 139 140macro GetTypedArrayAccessor(elementsKindParam: ElementsKind): 141 TypedArrayAccessor { 142 let elementsKind = elementsKindParam; 143 if (IsElementsKindGreaterThanOrEqual( 144 elementsKind, kFirstRabGsabFixedTypedArrayElementsKind)) { 145 elementsKind = %RawDownCast<ElementsKind>( 146 elementsKind - kFirstRabGsabFixedTypedArrayElementsKind + 147 kFirstFixedTypedArrayElementsKind); 148 } 149 if (IsElementsKindGreaterThan(elementsKind, ElementsKind::UINT32_ELEMENTS)) { 150 if (elementsKind == ElementsKind::INT32_ELEMENTS) { 151 return GetTypedArrayAccessor<Int32Elements>(); 152 } else if (elementsKind == ElementsKind::FLOAT32_ELEMENTS) { 153 return GetTypedArrayAccessor<Float32Elements>(); 154 } else if (elementsKind == ElementsKind::FLOAT64_ELEMENTS) { 155 return GetTypedArrayAccessor<Float64Elements>(); 156 } else if (elementsKind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { 157 return GetTypedArrayAccessor<Uint8ClampedElements>(); 158 } else if (elementsKind == ElementsKind::BIGUINT64_ELEMENTS) { 159 return GetTypedArrayAccessor<BigUint64Elements>(); 160 } else if (elementsKind == ElementsKind::BIGINT64_ELEMENTS) { 161 return GetTypedArrayAccessor<BigInt64Elements>(); 162 } 163 } else { 164 if (elementsKind == ElementsKind::UINT8_ELEMENTS) { 165 return GetTypedArrayAccessor<Uint8Elements>(); 166 } else if (elementsKind == ElementsKind::INT8_ELEMENTS) { 167 return GetTypedArrayAccessor<Int8Elements>(); 168 } else if (elementsKind == ElementsKind::UINT16_ELEMENTS) { 169 return GetTypedArrayAccessor<Uint16Elements>(); 170 } else if (elementsKind == ElementsKind::INT16_ELEMENTS) { 171 return GetTypedArrayAccessor<Int16Elements>(); 172 } else if (elementsKind == ElementsKind::UINT32_ELEMENTS) { 173 return GetTypedArrayAccessor<Uint32Elements>(); 174 } 175 } 176 unreachable; 177} 178 179extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( 180 JSTypedArray, ByteArray, uintptr): void; 181extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( 182 JSTypedArray, RawPtr, uintptr): void; 183extern macro IsJSArrayBufferViewDetachedOrOutOfBounds(JSArrayBufferView): 184 never labels DetachedOrOutOfBounds, NotDetachedNorOutOfBounds; 185extern macro IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(JSArrayBufferView): 186 bool; 187 188// AttachedJSTypedArray guards that the array's buffer is not detached. 189transient type AttachedJSTypedArray extends JSTypedArray; 190 191macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray 192 labels DetachedOrOutOfBounds { 193 try { 194 IsJSArrayBufferViewDetachedOrOutOfBounds(array) 195 otherwise DetachedOrOutOfBounds, NotDetachedNorOutOfBounds; 196 } label NotDetachedNorOutOfBounds { 197 return %RawDownCast<AttachedJSTypedArray>(array); 198 } 199} 200 201struct AttachedJSTypedArrayAndLength { 202 array: AttachedJSTypedArray; 203 length: uintptr; 204} 205 206macro EnsureAttachedAndReadLength(array: JSTypedArray): 207 AttachedJSTypedArrayAndLength 208 labels DetachedOrOutOfBounds { 209 const length = LoadJSTypedArrayLengthAndCheckDetached(array) 210 otherwise DetachedOrOutOfBounds; 211 return AttachedJSTypedArrayAndLength{ 212 array: %RawDownCast<AttachedJSTypedArray>(array), 213 length: length 214 }; 215} 216 217struct AttachedJSTypedArrayWitness { 218 macro GetStable(): JSTypedArray { 219 return this.stable; 220 } 221 222 macro RecheckIndex(index: uintptr): void labels DetachedOrOutOfBounds { 223 const length = LoadJSTypedArrayLengthAndCheckDetached(this.stable) 224 otherwise DetachedOrOutOfBounds; 225 if (index >= length) { 226 goto DetachedOrOutOfBounds; 227 } 228 this.unstable = %RawDownCast<AttachedJSTypedArray>(this.stable); 229 } 230 231 macro Load(implicit context: Context)(k: uintptr): JSAny { 232 const lf: LoadNumericFn = this.loadfn; 233 return lf(this.unstable, k); 234 } 235 236 stable: JSTypedArray; 237 unstable: AttachedJSTypedArray; 238 loadfn: LoadNumericFn; 239} 240 241macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray): 242 AttachedJSTypedArrayWitness { 243 const kind = array.elements_kind; 244 const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind); 245 return AttachedJSTypedArrayWitness{ 246 stable: array, 247 unstable: array, 248 loadfn: accessor.loadNumericFn 249 }; 250} 251 252macro KindForArrayType<T : type extends ElementsKind>(): constexpr ElementsKind; 253KindForArrayType<Uint8Elements>(): constexpr ElementsKind { 254 return ElementsKind::UINT8_ELEMENTS; 255} 256KindForArrayType<Int8Elements>(): constexpr ElementsKind { 257 return ElementsKind::INT8_ELEMENTS; 258} 259KindForArrayType<Uint16Elements>(): constexpr ElementsKind { 260 return ElementsKind::UINT16_ELEMENTS; 261} 262KindForArrayType<Int16Elements>(): constexpr ElementsKind { 263 return ElementsKind::INT16_ELEMENTS; 264} 265KindForArrayType<Uint32Elements>(): constexpr ElementsKind { 266 return ElementsKind::UINT32_ELEMENTS; 267} 268KindForArrayType<Int32Elements>(): constexpr ElementsKind { 269 return ElementsKind::INT32_ELEMENTS; 270} 271KindForArrayType<Float32Elements>(): constexpr ElementsKind { 272 return ElementsKind::FLOAT32_ELEMENTS; 273} 274KindForArrayType<Float64Elements>(): constexpr ElementsKind { 275 return ElementsKind::FLOAT64_ELEMENTS; 276} 277KindForArrayType<Uint8ClampedElements>(): constexpr ElementsKind { 278 return ElementsKind::UINT8_CLAMPED_ELEMENTS; 279} 280KindForArrayType<BigUint64Elements>(): constexpr ElementsKind { 281 return ElementsKind::BIGUINT64_ELEMENTS; 282} 283KindForArrayType<BigInt64Elements>(): constexpr ElementsKind { 284 return ElementsKind::BIGINT64_ELEMENTS; 285} 286 287builtin LoadTypedElement<T : type extends ElementsKind>( 288 array: JSTypedArray, index: uintptr): Numeric { 289 return LoadFixedTypedArrayElementAsTagged( 290 array.data_ptr, index, KindForArrayType<T>()); 291} 292 293builtin StoreTypedElementNumeric<T : type extends ElementsKind>( 294 context: Context, typedArray: JSTypedArray, index: uintptr, 295 value: Numeric): Smi { 296 StoreJSTypedArrayElementFromNumeric( 297 context, typedArray, index, value, KindForArrayType<T>()); 298 return kStoreSucceded; 299} 300 301// Returns True on sucess or False if the typedArrays was detached. 302builtin StoreTypedElementJSAny<T : type extends ElementsKind>( 303 context: Context, typedArray: JSTypedArray, index: uintptr, 304 value: JSAny): Smi { 305 try { 306 StoreJSTypedArrayElementFromTagged( 307 context, typedArray, index, value, KindForArrayType<T>()) 308 otherwise IfDetached; 309 } label IfDetached { 310 return kStoreFailureArrayDetached; 311 } 312 return kStoreSucceded; 313} 314} 315