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. 11 type Uint8Elements extends ElementsKind; 12 type Int8Elements extends ElementsKind; 13 type Uint16Elements extends ElementsKind; 14 type Int16Elements extends ElementsKind; 15 type Uint32Elements extends ElementsKind; 16 type Int32Elements extends ElementsKind; 17 type Float32Elements extends ElementsKind; 18 type Float64Elements extends ElementsKind; 19 type Uint8ClampedElements extends ElementsKind; 20 type BigUint64Elements extends ElementsKind; 21 type BigInt64Elements extends ElementsKind; 22 23 @export 24 struct TypedArrayElementsInfo { 25 // Calculates the number of bytes required for specified number of elements. 26 macro CalculateByteLength(length: uintptr): uintptr labels IfInvalid { 27 if (length > kTypedArrayMaxLength) goto IfInvalid; 28 const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2; 29 if (length > maxArrayLength) goto IfInvalid; 30 const byteLength = length << this.sizeLog2; 31 return byteLength; 32 } 33 34 // Calculates the maximum number of elements supported by a specified number 35 // of bytes. 36 macro CalculateLength(byteLength: uintptr): uintptr labels IfInvalid { 37 const length = byteLength >>> this.sizeLog2; 38 if (length > kTypedArrayMaxLength) goto IfInvalid; 39 return length; 40 } 41 42 // Determines if `bytes` (byte offset or length) cannot be evenly divided by 43 // element size. 44 macro IsUnaligned(bytes: uintptr): bool { 45 // Exploits the fact the element size is a power of 2. Determining whether 46 // there is remainder (not aligned) can be achieved efficiently with bit 47 // masking. Shift is safe as sizeLog2 can be 3 at most (see 48 // ElementsKindToShiftSize). 49 return (bytes & ((1 << this.sizeLog2) - 1)) != 0; 50 } 51 52 sizeLog2: uintptr; 53 kind: ElementsKind; 54 } 55 extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number): 56 void; 57 extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray( 58 Context, JSAny, constexpr string): JSTypedArray; 59 60 extern macro TypedArrayBuiltinsAssembler::CallCMemcpy( 61 RawPtr, RawPtr, uintptr): void; 62 extern macro TypedArrayBuiltinsAssembler::CallCMemmove( 63 RawPtr, RawPtr, uintptr): void; 64 extern macro TypedArrayBuiltinsAssembler::CallCMemset( 65 RawPtr, intptr, uintptr): void; 66 extern macro TypedArrayBuiltinsAssembler::GetBuffer( 67 implicit context: Context)(JSTypedArray): JSArrayBuffer; 68 extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo( 69 JSTypedArray): TypedArrayElementsInfo; 70 extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map): 71 TypedArrayElementsInfo; 72 extern macro TypedArrayBuiltinsAssembler::IsUint8ElementsKind(ElementsKind): 73 bool; 74 extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind( 75 ElementsKind): bool; 76 extern macro LoadFixedTypedArrayElementAsTagged( 77 RawPtr, uintptr, constexpr ElementsKind): Numeric; 78 extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( 79 Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind); 80 extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged( 81 Context, JSTypedArray, uintptr, JSAny, 82 constexpr ElementsKind) labels IfDetached; 83 84 type LoadNumericFn = builtin(Context, JSTypedArray, uintptr) => Numeric; 85 type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi; 86 type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi; 87 88 // The result codes returned by StoreNumericFn and StoreJSAnyFn builtins. 89 const kStoreSucceded: Smi = 0; 90 const kStoreFailureArrayDetached: Smi = 1; 91 92 struct TypedArrayAccessor { 93 macro LoadNumeric( 94 context: Context, array: JSTypedArray, index: uintptr): Numeric { 95 const loadfn: LoadNumericFn = this.loadNumericFn; 96 return loadfn(context, array, index); 97 } 98 99 macro StoreNumeric( 100 context: Context, array: JSTypedArray, index: uintptr, value: Numeric) { 101 const storefn: StoreNumericFn = this.storeNumericFn; 102 const result = storefn(context, array, index, value); 103 assert(result == kStoreSucceded); 104 } 105 106 macro StoreJSAny( 107 context: Context, array: JSTypedArray, index: uintptr, value: JSAny) 108 labels IfDetached { 109 const storefn: StoreJSAnyFn = this.storeJSAnyFn; 110 const result = storefn(context, array, index, value); 111 if (result == kStoreFailureArrayDetached) { 112 goto IfDetached; 113 } 114 assert(result == kStoreSucceded); 115 } 116 117 loadNumericFn: LoadNumericFn; 118 storeNumericFn: StoreNumericFn; 119 storeJSAnyFn: StoreJSAnyFn; 120 } 121 122 macro GetTypedArrayAccessor<T : type extends ElementsKind>(): 123 TypedArrayAccessor { 124 const loadNumericFn = LoadTypedElement<T>; 125 const storeNumericFn = StoreTypedElementNumeric<T>; 126 const storeJSAnyFn = StoreTypedElementJSAny<T>; 127 return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn}; 128 } 129 130 macro GetTypedArrayAccessor(elementsKind: ElementsKind): TypedArrayAccessor { 131 if (IsElementsKindGreaterThan( 132 elementsKind, ElementsKind::UINT32_ELEMENTS)) { 133 if (elementsKind == ElementsKind::INT32_ELEMENTS) { 134 return GetTypedArrayAccessor<Int32Elements>(); 135 } else if (elementsKind == ElementsKind::FLOAT32_ELEMENTS) { 136 return GetTypedArrayAccessor<Float32Elements>(); 137 } else if (elementsKind == ElementsKind::FLOAT64_ELEMENTS) { 138 return GetTypedArrayAccessor<Float64Elements>(); 139 } else if (elementsKind == ElementsKind::UINT8_CLAMPED_ELEMENTS) { 140 return GetTypedArrayAccessor<Uint8ClampedElements>(); 141 } else if (elementsKind == ElementsKind::BIGUINT64_ELEMENTS) { 142 return GetTypedArrayAccessor<BigUint64Elements>(); 143 } else if (elementsKind == ElementsKind::BIGINT64_ELEMENTS) { 144 return GetTypedArrayAccessor<BigInt64Elements>(); 145 } 146 } else { 147 if (elementsKind == ElementsKind::UINT8_ELEMENTS) { 148 return GetTypedArrayAccessor<Uint8Elements>(); 149 } else if (elementsKind == ElementsKind::INT8_ELEMENTS) { 150 return GetTypedArrayAccessor<Int8Elements>(); 151 } else if (elementsKind == ElementsKind::UINT16_ELEMENTS) { 152 return GetTypedArrayAccessor<Uint16Elements>(); 153 } else if (elementsKind == ElementsKind::INT16_ELEMENTS) { 154 return GetTypedArrayAccessor<Int16Elements>(); 155 } else if (elementsKind == ElementsKind::UINT32_ELEMENTS) { 156 return GetTypedArrayAccessor<Uint32Elements>(); 157 } 158 } 159 unreachable; 160 } 161 162 extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( 163 JSTypedArray, ByteArray, uintptr): void; 164 extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( 165 JSTypedArray, RawPtr, uintptr): void; 166 167 // AttachedJSTypedArray guards that the array's buffer is not detached. 168 transient type AttachedJSTypedArray extends JSTypedArray; 169 170 macro EnsureAttached(array: JSTypedArray): AttachedJSTypedArray 171 labels Detached { 172 if (IsDetachedBuffer(array.buffer)) goto Detached; 173 return %RawDownCast<AttachedJSTypedArray>(array); 174 } 175 176 struct AttachedJSTypedArrayWitness { 177 macro Get(): AttachedJSTypedArray { 178 return this.unstable; 179 } 180 181 macro GetStable(): JSTypedArray { 182 return this.stable; 183 } 184 185 macro Recheck() labels Detached { 186 if (IsDetachedBuffer(this.stable.buffer)) goto Detached; 187 this.unstable = %RawDownCast<AttachedJSTypedArray>(this.stable); 188 } 189 190 macro Load(implicit context: Context)(k: uintptr): JSAny { 191 const lf: LoadNumericFn = this.loadfn; 192 return lf(context, this.unstable, k); 193 } 194 195 stable: JSTypedArray; 196 unstable: AttachedJSTypedArray; 197 loadfn: LoadNumericFn; 198 } 199 200 macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray): 201 AttachedJSTypedArrayWitness { 202 const kind = array.elements_kind; 203 const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind); 204 return AttachedJSTypedArrayWitness{ 205 stable: array, 206 unstable: array, 207 loadfn: accessor.loadNumericFn 208 }; 209 } 210 211 macro KindForArrayType<T : type extends ElementsKind>(): 212 constexpr ElementsKind; 213 KindForArrayType<Uint8Elements>(): constexpr ElementsKind { 214 return ElementsKind::UINT8_ELEMENTS; 215 } 216 KindForArrayType<Int8Elements>(): constexpr ElementsKind { 217 return ElementsKind::INT8_ELEMENTS; 218 } 219 KindForArrayType<Uint16Elements>(): constexpr ElementsKind { 220 return ElementsKind::UINT16_ELEMENTS; 221 } 222 KindForArrayType<Int16Elements>(): constexpr ElementsKind { 223 return ElementsKind::INT16_ELEMENTS; 224 } 225 KindForArrayType<Uint32Elements>(): constexpr ElementsKind { 226 return ElementsKind::UINT32_ELEMENTS; 227 } 228 KindForArrayType<Int32Elements>(): constexpr ElementsKind { 229 return ElementsKind::INT32_ELEMENTS; 230 } 231 KindForArrayType<Float32Elements>(): constexpr ElementsKind { 232 return ElementsKind::FLOAT32_ELEMENTS; 233 } 234 KindForArrayType<Float64Elements>(): constexpr ElementsKind { 235 return ElementsKind::FLOAT64_ELEMENTS; 236 } 237 KindForArrayType<Uint8ClampedElements>(): constexpr ElementsKind { 238 return ElementsKind::UINT8_CLAMPED_ELEMENTS; 239 } 240 KindForArrayType<BigUint64Elements>(): constexpr ElementsKind { 241 return ElementsKind::BIGUINT64_ELEMENTS; 242 } 243 KindForArrayType<BigInt64Elements>(): constexpr ElementsKind { 244 return ElementsKind::BIGINT64_ELEMENTS; 245 } 246 247 builtin LoadTypedElement<T : type extends ElementsKind>( 248 _context: Context, array: JSTypedArray, index: uintptr): Numeric { 249 return LoadFixedTypedArrayElementAsTagged( 250 array.data_ptr, index, KindForArrayType<T>()); 251 } 252 253 builtin StoreTypedElementNumeric<T : type extends ElementsKind>( 254 context: Context, typedArray: JSTypedArray, index: uintptr, 255 value: Numeric): Smi { 256 StoreJSTypedArrayElementFromNumeric( 257 context, typedArray, index, value, KindForArrayType<T>()); 258 return kStoreSucceded; 259 } 260 261 // Returns True on sucess or False if the typedArrays was detached. 262 builtin StoreTypedElementJSAny<T : type extends ElementsKind>( 263 context: Context, typedArray: JSTypedArray, index: uintptr, 264 value: JSAny): Smi { 265 try { 266 StoreJSTypedArrayElementFromTagged( 267 context, typedArray, index, value, KindForArrayType<T>()) 268 otherwise IfDetached; 269 } 270 label IfDetached { 271 return kStoreFailureArrayDetached; 272 } 273 return kStoreSucceded; 274 } 275} 276