1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/builtins/builtins_arraybuffer.h" 17 18#include <typeinfo> 19 20#include "ecmascript/interpreter/interpreter.h" 21#include "ecmascript/js_function.h" 22#include "ecmascript/js_object-inl.h" 23#include "ecmascript/base/typed_array_helper-inl.h" 24 25#include "cstdio" 26#include "cstring" 27 28namespace panda::ecmascript::builtins { 29using TypedArrayHelper = base::TypedArrayHelper; 30// 24.1.2.1 ArrayBuffer(length) 31JSTaggedValue BuiltinsArrayBuffer::ArrayBufferConstructor(EcmaRuntimeCallInfo *argv) 32{ 33 ASSERT(argv); 34 JSThread *thread = argv->GetThread(); 35 BUILTINS_API_TRACE(thread, ArrayBuffer, Constructor); 36 [[maybe_unused]] EcmaHandleScope handleScope(thread); 37 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 38 // 1. If NewTarget is undefined, throw a TypeError exception. 39 if (newTarget->IsUndefined()) { 40 THROW_TYPE_ERROR_AND_RETURN(thread, "newtarget is undefined", JSTaggedValue::Exception()); 41 } 42 JSHandle<JSTaggedValue> lengthHandle = GetCallArg(argv, 0); 43 JSTaggedNumber lenNum = JSTaggedValue::ToIndex(thread, lengthHandle); 44 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 45 uint64_t length = lenNum.GetNumber(); 46 return AllocateArrayBuffer(thread, newTarget, length); 47} 48 49// 24.1.3.1 ArrayBuffer.isView(arg) 50JSTaggedValue BuiltinsArrayBuffer::IsView(EcmaRuntimeCallInfo *argv) 51{ 52 ASSERT(argv); 53 JSThread *thread = argv->GetThread(); 54 BUILTINS_API_TRACE(thread, ArrayBuffer, IsView); 55 [[maybe_unused]] EcmaHandleScope handleScope(thread); 56 JSHandle<JSTaggedValue> arg = GetCallArg(argv, 0); 57 // 1. If Type(arg) is not Object, return false. 58 if (!arg->IsECMAObject()) { 59 return BuiltinsArrayBuffer::GetTaggedBoolean(false); 60 } 61 // 2. If arg has a [[ViewedArrayBuffer]] internal slot, return true. 62 if (arg->IsDataView() || arg->IsTypedArray()) { 63 return BuiltinsArrayBuffer::GetTaggedBoolean(true); 64 } 65 // 3. Return false. 66 return BuiltinsArrayBuffer::GetTaggedBoolean(false); 67} 68 69// 24.1.3.3 get ArrayBuffer [ @@species ] 70JSTaggedValue BuiltinsArrayBuffer::Species(EcmaRuntimeCallInfo *argv) 71{ 72 ASSERT(argv); 73 BUILTINS_API_TRACE(argv->GetThread(), ArrayBuffer, Species); 74 return GetThis(argv).GetTaggedValue(); 75} 76 77// 24.1.4.1 get ArrayBuffer.prototype.byteLength 78JSTaggedValue BuiltinsArrayBuffer::GetByteLength(EcmaRuntimeCallInfo *argv) 79{ 80 ASSERT(argv); 81 JSThread *thread = argv->GetThread(); 82 BUILTINS_API_TRACE(thread, ArrayBuffer, GetByteLength); 83 [[maybe_unused]] EcmaHandleScope handleScope(thread); 84 85 // 1. Let O be the this value. 86 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 87 // 2. If Type(O) is not Object, throw a TypeError exception. 88 if (!thisHandle->IsECMAObject()) { 89 THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception()); 90 } 91 // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. 92 if (!thisHandle->IsArrayBuffer()) { 93 THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); 94 } 95 // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. 96 if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { 97 THROW_TYPE_ERROR_AND_RETURN(thread, "IsDetachedBuffer", JSTaggedValue::Exception()); 98 } 99 JSHandle<JSArrayBuffer> arrBuf(thisHandle); 100 // 5. Let length be the value of O’s [[ArrayBufferByteLength]] internal slot. 101 uint32_t length = arrBuf->GetArrayBufferByteLength(); 102 // 6. Return length. 103 return JSTaggedValue(length); 104} 105 106// 24.1.4.3 ArrayBuffer.prototype.slice(start, end) 107JSTaggedValue BuiltinsArrayBuffer::Slice(EcmaRuntimeCallInfo *argv) 108{ 109 ASSERT(argv); 110 JSThread *thread = argv->GetThread(); 111 BUILTINS_API_TRACE(thread, ArrayBuffer, Slice); 112 [[maybe_unused]] EcmaHandleScope handleScope(thread); 113 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 114 // 1. Let O be the this value. 115 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 116 // 2. If Type(O) is not Object, throw a TypeError exception. 117 if (!thisHandle->IsHeapObject()) { 118 THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception()); 119 } 120 JSHandle<JSArrayBuffer> arrBuf(thisHandle); 121 // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. 122 if (!thisHandle->IsArrayBuffer()) { 123 THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); 124 } 125 // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. 126 if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { 127 THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception()); 128 } 129 // 5. Let len be the value of O’s [[ArrayBufferByteLength]] internal slot. 130 int32_t len = static_cast<int32_t>(arrBuf->GetArrayBufferByteLength()); 131 JSHandle<JSTaggedValue> startHandle = GetCallArg(argv, 0); 132 // 6. Let relativeStart be ToInteger(start). 133 JSTaggedNumber relativeStart = JSTaggedValue::ToInteger(thread, startHandle); 134 // 7. ReturnIfAbrupt(relativeStart). 135 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 136 int32_t start = base::NumberHelper::DoubleInRangeInt32(relativeStart.GetNumber()); 137 int32_t end = 0; 138 int32_t first = 0; 139 int32_t last = 0; 140 // 8. If relativeStart < 0, let first be max((len + relativeStart),0); else let first be min(relativeStart, len). 141 if (start < 0) { 142 first = std::max((len + start), 0); 143 } else { 144 first = std::min(start, len); 145 } 146 // 9. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). 147 JSHandle<JSTaggedValue> endHandle = GetCallArg(argv, 1); 148 if (endHandle->IsUndefined()) { 149 end = len; 150 } else { 151 JSTaggedNumber relativeEnd = JSTaggedValue::ToInteger(thread, endHandle); 152 // 10. ReturnIfAbrupt(relativeEnd). 153 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 154 end = base::NumberHelper::DoubleInRangeInt32(relativeEnd.GetNumber()); 155 } 156 // 11. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). 157 if (end < 0) { 158 last = std::max((len + end), 0); 159 } else { 160 last = std::min(end, len); 161 } 162 // 12. Let newLen be max(final-first,0). 163 uint32_t newLen = std::max((last - first), 0); 164 // 13. Let ctor be SpeciesConstructor(O, %ArrayBuffer%). 165 JSHandle<JSTaggedValue> defaultConstructor = env->GetArrayBufferFunction(); 166 JSHandle<JSObject> objHandle(thisHandle); 167 JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); 168 // 14. ReturnIfAbrupt(ctor). 169 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 170 // 15. Let new be Construct(ctor, «newLen»). 171 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 172 EcmaRuntimeCallInfo *info = 173 EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 1); 174 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 175 info->SetCallArg(JSTaggedValue(newLen)); 176 JSTaggedValue taggedNewArrBuf = JSFunction::Construct(info); 177 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 178 JSHandle<JSTaggedValue> newArrBuf(thread, taggedNewArrBuf); 179 // 16. ReturnIfAbrupt(new). 180 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 181 // 17. If new does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. 182 if (!newArrBuf->IsArrayBuffer()) { 183 THROW_TYPE_ERROR_AND_RETURN(thread, "don't have bufferdata internal slot", JSTaggedValue::Exception()); 184 } 185 // 18. If IsDetachedBuffer(new) is true, throw a TypeError exception. 186 if (IsDetachedBuffer(newArrBuf.GetTaggedValue())) { 187 THROW_TYPE_ERROR_AND_RETURN(thread, "new arrayBuffer IsDetachedBuffer", JSTaggedValue::Exception()); 188 } 189 // 19. If SameValue(new, O) is true, throw a TypeError exception. 190 if (JSTaggedValue::SameValue(newArrBuf.GetTaggedValue(), thisHandle.GetTaggedValue())) { 191 THROW_TYPE_ERROR_AND_RETURN(thread, "value of new arraybuffer and this is same", JSTaggedValue::Exception()); 192 } 193 JSHandle<JSArrayBuffer> newJsArrBuf(newArrBuf); 194 // 20. If the value of new’s [[ArrayBufferByteLength]] internal slot < newLen, throw a TypeError exception. 195 uint32_t newArrBufLen = newJsArrBuf->GetArrayBufferByteLength(); 196 if (newArrBufLen < newLen) { 197 THROW_TYPE_ERROR_AND_RETURN(thread, "new array buffer length smaller than newlen", JSTaggedValue::Exception()); 198 } 199 // 21. NOTE: Side-effects of the above steps may have detached O. 200 // 22. If IsDetachedBuffer(O) is true, throw a TypeError exception. 201 if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { 202 THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception()); 203 } 204 if (newLen > 0) { 205 // 23. Let fromBuf be the value of O’s [[ArrayBufferData]] internal slot. 206 void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue()); 207 // 24. Let toBuf be the value of new’s [[ArrayBufferData]] internal slot. 208 void *toBuf = GetDataPointFromBuffer(newJsArrBuf.GetTaggedValue()); 209 // 25. Perform CopyDataBlockBytes(toBuf, fromBuf, first, newLen). 210 JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, first, newLen); 211 } 212 // Return new. 213 return newArrBuf.GetTaggedValue(); 214} 215 216// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength) 217JSTaggedValue BuiltinsArrayBuffer::AllocateArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget, 218 uint64_t byteLength) 219{ 220 BUILTINS_API_TRACE(thread, ArrayBuffer, AllocateArrayBuffer); 221 /** 222 * 1. Let obj be OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", 223 * «[[ArrayBufferData]], [[ArrayBufferByteLength]]» ). 224 * */ 225 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 226 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 227 JSHandle<JSTaggedValue> arrBufFunc = env->GetArrayBufferFunction(); 228 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(arrBufFunc), newTarget); 229 // 2. ReturnIfAbrupt 230 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 231 // 4. Let block be CreateByteDataBlock(byteLength). 232 if (byteLength > INT_MAX) { 233 THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception()); 234 } 235 uint64_t totalNativeSize = static_cast<uint64_t>(thread->GetNativeAreaAllocator()->GetArrayBufferNativeSize()); 236 if (UNLIKELY(totalNativeSize > MAX_NATIVE_SIZE_LIMIT)) { 237 THROW_RANGE_ERROR_AND_RETURN(thread, NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE, JSTaggedValue::Exception()); 238 } 239 uint32_t arrayByteLength = static_cast<uint32_t>(byteLength); 240 JSHandle<JSArrayBuffer> arrayBuffer(obj); 241 // 6. Set obj’s [[ArrayBufferData]] internal slot to block. 242 factory->NewJSArrayBufferData(arrayBuffer, arrayByteLength); 243 // 7. Set obj’s [[ArrayBufferByteLength]] internal slot to byteLength. 244 arrayBuffer->SetArrayBufferByteLength(arrayByteLength); 245 // 8. Return obj. 246 return arrayBuffer.GetTaggedValue(); 247} 248 249// 24.1.1.2 IsDetachedBuffer() 250void BuiltinsArrayBuffer::IsDetachedBuffer(JSThread *thread, const JSHandle<JSTypedArray> &arrayBuffer) 251{ 252 JSTaggedValue detachedBuffer = arrayBuffer->GetViewedArrayBufferOrByteArray(); 253 if (IsDetachedBuffer(detachedBuffer)) { 254 THROW_TYPE_ERROR(thread, "The ArrayBuffer of this value is detached buffer."); 255 } 256} 257 258bool BuiltinsArrayBuffer::IsDetachedBuffer(JSTaggedValue arrayBuffer) 259{ 260 if (arrayBuffer.IsByteArray()) { 261 return false; 262 } 263 // 1. Assert: Type(arrayBuffer) is Object and it has an [[ArrayBufferData]] internal slot. 264 ASSERT(arrayBuffer.IsArrayBuffer() || arrayBuffer.IsSharedArrayBuffer()); 265 JSArrayBuffer *buffer = JSArrayBuffer::Cast(arrayBuffer.GetTaggedObject()); 266 if (buffer == nullptr) { 267 LOG_ECMA(FATAL) << "BuiltinsArrayBuffer::IsDetachedBuffer:buffer is nullptr"; 268 } 269 JSTaggedValue dataSlot = buffer->GetArrayBufferData(); 270 // 2. If arrayBuffer’s [[ArrayBufferData]] internal slot is null, return true. 271 // 3. Return false. 272 return dataSlot.IsNull(); 273} 274 275// 24.1.1.4 276JSTaggedValue BuiltinsArrayBuffer::CloneArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &srcBuffer, 277 uint32_t srcByteOffset, JSHandle<JSTaggedValue> constructor) 278{ 279 BUILTINS_API_TRACE(thread, ArrayBuffer, CloneArrayBuffer); 280 // 1. Assert: Type(srcBuffer) is Object and it has an [[ArrayBufferData]] internal slot. 281 ASSERT(srcBuffer->IsArrayBuffer() || srcBuffer->IsSharedArrayBuffer() || srcBuffer->IsByteArray()); 282 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 283 // 2. If cloneConstructor is not present 284 if (constructor->IsUndefined()) { 285 // a. Let cloneConstructor be SpeciesConstructor(srcBuffer, %ArrayBuffer%). 286 JSHandle<JSTaggedValue> defaultConstructor = env->GetArrayBufferFunction(); 287 JSHandle<JSObject> objHandle(srcBuffer); 288 constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); 289 // b. ReturnIfAbrupt(cloneConstructor). 290 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 291 // c. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. 292 if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) { 293 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception()); 294 } else { 295 ASSERT(constructor->IsConstructor()); 296 } 297 } 298 // 4. Let srcLength be the value of srcBuffer’s [[ArrayBufferByteLength]] internal slot. 299 uint32_t srcLen = 0; 300 int32_t cloneLen = 0; 301 if (srcBuffer->IsByteArray()) { 302 JSHandle<ByteArray> byteArrayBuf(srcBuffer); 303 srcLen = byteArrayBuf->GetArrayLength(); 304 int32_t byteLen = static_cast<int32_t>(byteArrayBuf->GetByteLength()); 305 // 5. Assert: srcByteOffset ≤ srcLength. 306 ASSERT(srcByteOffset <= srcLen); 307 // 6. Let cloneLength be (srcLength – srcByteOffset) * byteLen. 308 cloneLen = static_cast<int32_t>(srcLen - srcByteOffset) * byteLen; 309 srcByteOffset *= static_cast<uint32_t>(byteLen); 310 } else { 311 JSHandle<JSArrayBuffer> arrBuf(srcBuffer); 312 srcLen = arrBuf->GetArrayBufferByteLength(); 313 // 5. Assert: srcByteOffset ≤ srcLength. 314 ASSERT(srcByteOffset <= srcLen); 315 // 6. Let cloneLength be srcLength – srcByteOffset. 316 cloneLen = static_cast<int32_t>(srcLen - srcByteOffset); 317 } 318 // 8. Let targetBuffer be AllocateArrayBuffer(cloneConstructor, cloneLength). 319 JSTaggedValue taggedBuf = AllocateArrayBuffer(thread, constructor, cloneLen); 320 // 9. ReturnIfAbrupt(targetBuffer). 321 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 322 // 10. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. 323 if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) { 324 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception()); 325 } 326 // 11. Let targetBlock be the value of targetBuffer’s [[ArrayBufferData]] internal slot. 327 JSHandle<JSArrayBuffer> newArrBuf(thread, taggedBuf); 328 // Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, cloneLength). 329 // 7. Let srcBlock be the value of srcBuffer’s [[ArrayBufferData]] internal slot. 330 if (cloneLen > 0) { 331 void *fromBuf = GetDataPointFromBuffer(srcBuffer.GetTaggedValue()); 332 void *toBuf = GetDataPointFromBuffer(taggedBuf); 333 JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, srcByteOffset, cloneLen); 334 } 335 return taggedBuf; 336} 337 338// 24.1.1.5 339// NOLINTNEXTLINE(readability-function-size) 340JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, 341 DataViewType type, bool littleEndian) 342{ 343 void *pointer = GetDataPointFromBuffer(arrBuf); 344 uint8_t *block = reinterpret_cast<uint8_t *>(pointer); 345 return GetValueFromBuffer(thread, byteIndex, block, type, littleEndian); 346} 347 348JSTaggedValue BuiltinsArrayBuffer::GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block, 349 DataViewType type, bool littleEndian) 350{ 351 ASSERT(block != nullptr); 352 switch (type) { 353 case DataViewType::UINT8: 354 case DataViewType::UINT8_CLAMPED: { 355 uint8_t res = block[byteIndex]; // NOLINT 356 return GetTaggedInt(res); 357 } 358 case DataViewType::INT8: { 359 uint8_t res = block[byteIndex]; // NOLINT 360 auto int8Res = static_cast<int8_t>(res); 361 return GetTaggedInt(int8Res); 362 } 363 case DataViewType::UINT16: 364 return GetValueFromBufferForInteger<uint16_t, NumberSize::UINT16>(block, byteIndex, littleEndian); 365 case DataViewType::INT16: 366 return GetValueFromBufferForInteger<int16_t, NumberSize::INT16>(block, byteIndex, littleEndian); 367 case DataViewType::UINT32: 368 return GetValueFromBufferForInteger<uint32_t, NumberSize::UINT32>(block, byteIndex, littleEndian); 369 case DataViewType::INT32: 370 return GetValueFromBufferForInteger<int32_t, NumberSize::INT32>(block, byteIndex, littleEndian); 371 case DataViewType::FLOAT32: 372 return GetValueFromBufferForFloat<float, UnionType32, NumberSize::FLOAT32>(block, byteIndex, littleEndian); 373 case DataViewType::FLOAT64: 374 return GetValueFromBufferForFloat<double, UnionType64, NumberSize::FLOAT64>(block, byteIndex, littleEndian); 375 case DataViewType::BIGINT64: 376 return GetValueFromBufferForBigInt<int64_t, NumberSize::BIGINT64>(thread, block, byteIndex, littleEndian); 377 case DataViewType::BIGUINT64: 378 return GetValueFromBufferForBigInt<uint64_t, NumberSize::BIGUINT64>(thread, block, byteIndex, littleEndian); 379 default: 380 break; 381 } 382 LOG_ECMA(FATAL) << "this branch is unreachable"; 383 UNREACHABLE(); 384} 385 386// 24.1.1.6 387JSTaggedValue BuiltinsArrayBuffer::SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, 388 DataViewType type, const JSHandle<JSTaggedValue> &value, 389 bool littleEndian) 390{ 391 if (UNLIKELY(IsBigIntElementType(type))) { 392 JSHandle<JSTaggedValue> arrBufHandle(thread, arrBuf); 393 switch (type) { 394 case DataViewType::BIGINT64: 395 SetValueInBufferForBigInt<int64_t>(thread, value, arrBufHandle, byteIndex, littleEndian); 396 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 397 break; 398 case DataViewType::BIGUINT64: 399 SetValueInBufferForBigInt<uint64_t>(thread, value, arrBufHandle, byteIndex, littleEndian); 400 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 401 break; 402 default: 403 LOG_ECMA(FATAL) << "this branch is unreachable"; 404 UNREACHABLE(); 405 } 406 return JSTaggedValue::Undefined(); 407 } 408 void *pointer = GetDataPointFromBuffer(arrBuf); 409 uint8_t *block = reinterpret_cast<uint8_t *>(pointer); 410 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, value.GetTaggedValue()); 411 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 412 double val = numberValue.GetNumber(); 413 return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian); 414} 415 416// es12 25.1.2.7 IsBigIntElementType ( type ) 417bool BuiltinsArrayBuffer::IsBigIntElementType(DataViewType type) 418{ 419 if (type == DataViewType::BIGINT64 || type == DataViewType::BIGUINT64) { 420 return true; 421 } 422 return false; 423} 424 425// es12 25.1.2.6 IsUnclampedIntegerElementType ( type ) 426bool BuiltinsArrayBuffer::IsUnclampedIntegerElementType(DataViewType type) 427{ 428 switch (type) { 429 case DataViewType::INT8: 430 case DataViewType::INT16: 431 case DataViewType::INT32: 432 case DataViewType::UINT8: 433 case DataViewType::UINT16: 434 case DataViewType::UINT32: 435 return true; 436 default: 437 return false; 438 } 439} 440 441template<typename T> 442void BuiltinsArrayBuffer::SetTypeData(uint8_t *block, T value, uint32_t index) 443{ 444 uint32_t sizeCount = sizeof(T); 445 uint8_t *res = reinterpret_cast<uint8_t *>(&value); 446 for (uint32_t i = 0; i < sizeCount; i++) { 447 *(block + index + i) = *(res + i); // NOLINT 448 } 449} 450 451template<typename T> 452void BuiltinsArrayBuffer::FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value) 453{ 454 ASSERT(byteBeginOffset != nullptr); 455 ASSERT(byteEndOffset != nullptr); 456 uint32_t sizeCount = sizeof(T); 457 if (sizeCount == 1) { 458 memset_s(byteBeginOffset, byteEndOffset-byteBeginOffset, value, byteEndOffset-byteBeginOffset); 459 } else { 460 uint8_t *resAddr = reinterpret_cast<uint8_t *>(&value); 461 for (uint8_t *addr = byteBeginOffset; addr < byteEndOffset; addr += sizeCount) { 462 for (uint32_t i = 0; i < sizeCount; ++i) { 463 *(addr + i) = *(resAddr + i); 464 } 465 } 466 } 467} 468 469template <typename T> 470T BuiltinsArrayBuffer::LittleEndianToBigEndian(T liValue) 471{ 472 uint8_t sizeCount = sizeof(T); 473 T biValue; 474 switch (sizeCount) { 475 case NumberSize::UINT16: 476 biValue = ((liValue & 0x00FF) << BITS_EIGHT) // NOLINT 477 | ((liValue & 0xFF00) >> BITS_EIGHT); // NOLINT 478 break; 479 case NumberSize::UINT32: 480 biValue = ((liValue & 0x000000FF) << BITS_TWENTY_FOUR) // NOLINT 481 | ((liValue & 0x0000FF00) << BITS_EIGHT) // NOLINT 482 | ((liValue & 0x00FF0000) >> BITS_EIGHT) // NOLINT 483 | ((liValue & 0xFF000000) >> BITS_TWENTY_FOUR); // NOLINT 484 break; 485 default: 486 LOG_ECMA(FATAL) << "this branch is unreachable"; 487 UNREACHABLE(); 488 break; 489 } 490 return biValue; 491} 492template <typename T> 493T BuiltinsArrayBuffer::LittleEndianToBigEndian64Bit(T liValue) 494{ 495 return ((liValue & 0x00000000000000FF) << BITS_FIFTY_SIX) // NOLINT 496 | ((liValue & 0x000000000000FF00) << BITS_FORTY) // NOLINT 497 | ((liValue & 0x0000000000FF0000) << BITS_TWENTY_FOUR) // NOLINT 498 | ((liValue & 0x00000000FF000000) << BITS_EIGHT) // NOLINT 499 | ((liValue & 0x000000FF00000000) >> BITS_EIGHT) // NOLINT 500 | ((liValue & 0x0000FF0000000000) >> BITS_TWENTY_FOUR) // NOLINT 501 | ((liValue & 0x00FF000000000000) >> BITS_FORTY) // NOLINT 502 | ((liValue & 0xFF00000000000000) >> BITS_FIFTY_SIX); // NOLINT 503} 504 505template<typename T, BuiltinsArrayBuffer::NumberSize size> 506JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForInteger(uint8_t *block, uint32_t byteIndex, bool littleEndian) 507{ 508 ASSERT(block != nullptr); 509 ASSERT_PRINT(std::is_integral_v<T>, "T must be integral"); 510 ASSERT_PRINT(sizeof(T) == size, "Invalid number size"); 511 ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); 512 513 ASSERT(size >= NumberSize::UINT16 || size <= NumberSize::FLOAT64); 514 T res = *reinterpret_cast<T *>(block + byteIndex); 515 if (!littleEndian) { 516 res = LittleEndianToBigEndian(res); 517 } 518 519 // uint32_t maybe overflow with TaggedInt 520 // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) 521 if constexpr (std::is_same_v<T, uint32_t>) { 522 // NOLINTNEXTLINE(clang-diagnostic-sign-compare) 523 if (res > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) { 524 return GetTaggedDouble(static_cast<double>(res)); 525 } 526 } 527 return GetTaggedInt(res); 528} 529 530template<typename T, typename UnionType, BuiltinsArrayBuffer::NumberSize size> 531JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForFloat(uint8_t *block, uint32_t byteIndex, bool littleEndian) 532{ 533 ASSERT(block != nullptr); 534 ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be correct type"); 535 ASSERT_PRINT(sizeof(T) == size, "Invalid number size"); 536 537 UnionType unionValue = {0}; 538 // NOLINTNEXTLINE(readability-braces-around-statements) 539 if constexpr (std::is_same_v<T, float>) { 540 unionValue.uValue = *reinterpret_cast<uint32_t *>(block + byteIndex); 541 uint32_t res = LittleEndianToBigEndian(unionValue.uValue); 542 return CommonConvert<T, uint32_t>(unionValue.value, res, littleEndian); 543 } else if constexpr (std::is_same_v<T, double>) { // NOLINTNEXTLINE(readability-braces-around-statements) 544 unionValue.uValue = *reinterpret_cast<uint64_t *>(block + byteIndex); 545 uint64_t res = LittleEndianToBigEndian64Bit(unionValue.uValue); 546 return CommonConvert<T, uint64_t>(unionValue.value, res, littleEndian); 547 } 548 549 return GetTaggedDouble(unionValue.value); 550} 551 552template<typename T1, typename T2> 553JSTaggedValue BuiltinsArrayBuffer::CommonConvert(T1 &value, T2 &res, bool littleEndian) 554{ 555 if (std::isnan(value) && !JSTaggedValue::IsImpureNaN(value)) { 556 return GetTaggedDouble(value); 557 } 558 if (!littleEndian) { 559 T1 d = base::bit_cast<T1>(res); 560 if (JSTaggedValue::IsImpureNaN(d)) { 561 return GetTaggedDouble(base::NAN_VALUE); 562 } 563 return GetTaggedDouble(d); 564 } else { 565 if (JSTaggedValue::IsImpureNaN(value)) { 566 return GetTaggedDouble(base::NAN_VALUE); 567 } 568 } 569 return GetTaggedDouble(value); 570} 571 572 573template<typename T, BuiltinsArrayBuffer::NumberSize size> 574JSTaggedValue BuiltinsArrayBuffer::GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block, 575 uint32_t byteIndex, bool littleEndian) 576{ 577 ASSERT(block != nullptr); 578 ASSERT_PRINT((std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t>), "T must be uint64_t/int64_t"); 579 auto pTmp = *reinterpret_cast<uint64_t *>(block + byteIndex); 580 if (!littleEndian) { 581 pTmp = LittleEndianToBigEndian64Bit(pTmp); 582 } 583 if constexpr (std::is_same_v<T, uint64_t>) { 584 return BigInt::Uint64ToBigInt(thread, pTmp).GetTaggedValue(); 585 } 586 return BigInt::Int64ToBigInt(thread, pTmp).GetTaggedValue(); 587} 588 589 590template<typename T> 591void BuiltinsArrayBuffer::SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex) 592{ 593 ASSERT_PRINT((std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>), "T must be int8/uint8"); 594 T res; 595 if (std::isnan(val) || std::isinf(val)) { 596 res = 0; 597 SetTypeData(block, res, byteIndex); 598 return; 599 } 600 auto int64Val = static_cast<int64_t>(val); 601 auto *resArr = reinterpret_cast<T *>(&int64Val); 602 res = *resArr; 603 SetTypeData(block, res, byteIndex); 604} 605 606void BuiltinsArrayBuffer::SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex) 607{ 608 uint8_t res; 609 if (std::isnan(val) || val <= 0) { 610 res = 0; 611 } else if (val > UINT8_MAX) { 612 res = UINT8_MAX; 613 } else { 614 // same as ToUint8Clamp 615 res = std::lrint(val); 616 } 617 SetTypeData(block, res, byteIndex); 618} 619 620template<typename T> 621void BuiltinsArrayBuffer::SetValueInBufferForInteger(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian) 622{ 623 ASSERT_PRINT(std::is_integral_v<T>, "T must be integral"); 624 ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); 625 T res; 626 if (std::isnan(val) || std::isinf(val)) { 627 res = 0; 628 SetTypeData(block, res, byteIndex); 629 return; 630 } 631 auto int64Val = static_cast<int64_t>(val); 632 // NOLINTNEXTLINE(readability-braces-around-statements) 633 if constexpr (std::is_same_v<T, uint16_t>) { 634 auto *pTmp = reinterpret_cast<int16_t *>(&int64Val); 635 int16_t tmp = *pTmp; 636 res = static_cast<T>(tmp); 637 } else { // NOLINTNEXTLINE(readability-braces-around-statements) 638 auto *pTmp = reinterpret_cast<T *>(&int64Val); 639 res = *pTmp; 640 } 641 642 if (!littleEndian) { 643 res = LittleEndianToBigEndian<T>(res); 644 } 645 SetTypeData(block, res, byteIndex); 646} 647 648template<typename T> 649void BuiltinsArrayBuffer::SetValueInBufferForFloat(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian) 650{ 651 ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be float type"); 652 auto data = static_cast<T>(val); 653 if (std::isnan(val)) { 654 SetTypeData(block, data, byteIndex); 655 return; 656 } 657 if (!littleEndian) { 658 if constexpr (std::is_same_v<T, float>) { 659 uint32_t res = base::bit_cast<uint32_t>(data); 660 data = base::bit_cast<T>(LittleEndianToBigEndian(res)); 661 } else if constexpr (std::is_same_v<T, double>) { 662 uint64_t res = base::bit_cast<uint64_t>(data); 663 data = base::bit_cast<T>(LittleEndianToBigEndian64Bit(res)); 664 } 665 } 666 SetTypeData(block, data, byteIndex); 667} 668 669template<typename T> 670void BuiltinsArrayBuffer::SetValueInBufferForBigInt(JSThread *thread, 671 const JSHandle<JSTaggedValue> &val, 672 JSHandle<JSTaggedValue> &arrBuf, 673 uint32_t byteIndex, bool littleEndian) 674{ 675 ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t"); 676 T value = 0; 677 bool lossless = true; 678 if constexpr(std::is_same_v<T, uint64_t>) { 679 BigInt::BigIntToUint64(thread, val, reinterpret_cast<uint64_t *>(&value), &lossless); 680 } else { 681 BigInt::BigIntToInt64(thread, val, reinterpret_cast<int64_t *>(&value), &lossless); 682 } 683 RETURN_IF_ABRUPT_COMPLETION(thread); 684 if (!littleEndian) { 685 value = LittleEndianToBigEndian64Bit<T>(value); 686 } 687 void *pointer = GetDataPointFromBuffer(arrBuf.GetTaggedValue()); 688 uint8_t *block = reinterpret_cast<uint8_t *>(pointer); 689 SetTypeData(block, value, byteIndex); 690} 691 692template<typename T> 693void BuiltinsArrayBuffer::SetValueInBufferForBigInt(JSThread *thread, 694 double val, uint8_t *block, 695 uint32_t byteIndex, bool littleEndian) 696{ 697 ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t"); 698 T value = 0; 699 bool lossless = true; 700 701 JSHandle<JSTaggedValue> valHandle(thread, GetTaggedDouble(val)); 702 if constexpr(std::is_same_v<T, uint64_t>) { 703 BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast<uint64_t *>(&value), &lossless); 704 } else { 705 BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast<int64_t *>(&value), &lossless); 706 } 707 RETURN_IF_ABRUPT_COMPLETION(thread); 708 if (!littleEndian) { 709 value = LittleEndianToBigEndian64Bit<T>(value); 710 } 711 SetTypeData(block, value, byteIndex); 712} 713 714JSTaggedValue BuiltinsArrayBuffer::FastSetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, 715 DataViewType type, double val, bool littleEndian) 716{ 717 // origin type maybe native JSType or shared JSType. 718 if (arrBuf.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(arrBuf)) { 719 return JSTaggedValue::Undefined(); 720 } 721 if (!arrBuf.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(arrBuf)) { 722 return JSTaggedValue::Undefined(); 723 } 724 void *pointer = GetDataPointFromBuffer(arrBuf); 725 uint8_t *block = reinterpret_cast<uint8_t *>(pointer); 726 return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian); 727} 728 729JSTaggedValue BuiltinsArrayBuffer::SetValueInBuffer(JSThread* thread, uint32_t byteIndex, uint8_t *block, 730 DataViewType type, double val, bool littleEndian) 731{ 732 switch (type) { 733 case DataViewType::UINT8: 734 SetValueInBufferForByte<uint8_t>(val, block, byteIndex); 735 break; 736 case DataViewType::UINT8_CLAMPED: 737 SetValueInBufferForUint8Clamped(val, block, byteIndex); 738 break; 739 case DataViewType::INT8: 740 SetValueInBufferForByte<int8_t>(val, block, byteIndex); 741 break; 742 case DataViewType::UINT16: 743 SetValueInBufferForInteger<uint16_t>(val, block, byteIndex, littleEndian); 744 break; 745 case DataViewType::INT16: 746 SetValueInBufferForInteger<int16_t>(val, block, byteIndex, littleEndian); 747 break; 748 case DataViewType::UINT32: 749 SetValueInBufferForInteger<uint32_t>(val, block, byteIndex, littleEndian); 750 break; 751 case DataViewType::INT32: 752 SetValueInBufferForInteger<int32_t>(val, block, byteIndex, littleEndian); 753 break; 754 case DataViewType::FLOAT32: 755 SetValueInBufferForFloat<float>(val, block, byteIndex, littleEndian); 756 break; 757 case DataViewType::FLOAT64: 758 SetValueInBufferForFloat<double>(val, block, byteIndex, littleEndian); 759 break; 760 case DataViewType::BIGINT64: 761 SetValueInBufferForBigInt<int64_t>(thread, val, block, byteIndex, littleEndian); 762 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 763 break; 764 case DataViewType::BIGUINT64: 765 SetValueInBufferForBigInt<uint64_t>(thread, val, block, byteIndex, littleEndian); 766 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 767 break; 768 default: 769 LOG_ECMA(FATAL) << "this branch is unreachable"; 770 UNREACHABLE(); 771 } 772 return JSTaggedValue::Undefined(); 773} 774 775void *BuiltinsArrayBuffer::GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset) 776{ 777 if (arrBuf.IsByteArray()) { 778 return reinterpret_cast<void *>(ToUintPtr(ByteArray::Cast(arrBuf.GetTaggedObject())->GetData()) + byteOffset); 779 } 780 781 JSArrayBuffer *arrayBuffer = JSArrayBuffer::Cast(arrBuf.GetTaggedObject()); 782 if (arrayBuffer == nullptr) { 783 LOG_ECMA(FATAL) << "BuiltinsArrayBuffer::GetDataPointFromBuffer:arrayBuffer is nullptr"; 784 UNREACHABLE(); 785 } 786 if (arrayBuffer->GetArrayBufferByteLength() == 0) { 787 LOG_ECMA(FATAL) << "BuiltinsArrayBuffer::GetDataPointFromBuffer:arrayBuffer length is 0"; 788 UNREACHABLE(); 789 } 790 791 JSTaggedValue data = arrayBuffer->GetArrayBufferData(); 792 return reinterpret_cast<void *>(ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject()) 793 ->GetExternalPointer()) + byteOffset); 794} 795 796JSTaggedValue BuiltinsArrayBuffer::TypedArrayToList(JSThread *thread, JSHandle<JSTypedArray>& items) 797{ 798 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 799 JSHandle<JSTaggedValue> bufferHandle(thread, items->GetViewedArrayBufferOrByteArray()); 800 uint32_t arrayLen = items->GetArrayLength(); 801 JSHandle<JSObject> newArrayHandle(thread, JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue()); 802 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 803 JSHandle<TaggedArray> oldElements(thread, newArrayHandle->GetElements()); 804 JSHandle<TaggedArray> elements = (oldElements->GetLength() < arrayLen) ? 805 factory->ExtendArray(oldElements, arrayLen) : oldElements; 806 newArrayHandle->SetElements(thread, elements); 807 uint32_t offset = items->GetByteOffset(); 808 uint32_t elementSize = TypedArrayHelper::GetElementSize(items); 809 DataViewType elementType = TypedArrayHelper::GetType(items); 810 uint32_t index = 0; 811 while (index < arrayLen) { 812 uint32_t byteIndex = index * elementSize + offset; 813 JSHandle<JSTaggedValue> result(thread, GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(), 814 byteIndex, elementType, true)); 815 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 816 ElementAccessor::Set(thread, newArrayHandle, index, result, true); 817 index++; 818 } 819 JSHandle<JSArray>(newArrayHandle)->SetArrayLength(thread, arrayLen); 820 return newArrayHandle.GetTaggedValue(); 821} 822 823template<typename T> 824void BuiltinsArrayBuffer::FastSetValueInBufferForByte(uint8_t *byteBeginOffset, 825 uint8_t *byteEndOffset, 826 double val) 827{ 828 ASSERT_PRINT(sizeof(T) == 1, "sizeof(T) must be one"); 829 ASSERT_PRINT((std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>), "T must be int8/uint8"); 830 T res; 831 if (std::isnan(val) || std::isinf(val)) { 832 res = 0; 833 } else { 834 auto int64Val = static_cast<int64_t>(val); 835 auto *resArr = reinterpret_cast<T *>(&int64Val); 836 res = *resArr; 837 } 838 FastSetTypeData(byteBeginOffset, byteEndOffset, res); 839} 840 841void BuiltinsArrayBuffer::FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset, 842 uint8_t *byteEndOffset, 843 double val) 844{ 845 uint8_t res; 846 if (std::isnan(val) || val <= 0) { 847 res = 0; 848 } else { 849 val = val >= UINT8_MAX ? UINT8_MAX : val; 850 constexpr double HALF = 0.5; 851 val = val == HALF ? 0 : std::round(val); 852 res = static_cast<uint64_t>(val); 853 } 854 FastSetTypeData(byteBeginOffset, byteEndOffset, res); 855} 856 857template<typename T> 858void BuiltinsArrayBuffer::FastSetValueInBufferForInteger(uint8_t *byteBeginOffset, 859 uint8_t *byteEndOffset, 860 double val, bool littleEndian) 861{ 862 ASSERT_PRINT(std::is_integral_v<T>, "T must be integral"); 863 ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); 864 T res; 865 if (std::isnan(val) || std::isinf(val)) { 866 res = 0; 867 } else { 868 auto int64Val = static_cast<int64_t>(val); 869 // NOLINTNEXTLINE(readability-braces-around-statements) 870 if constexpr (std::is_same_v<T, uint16_t>) { 871 auto *pTmp = reinterpret_cast<int16_t *>(&int64Val); 872 int16_t tmp = *pTmp; 873 res = static_cast<T>(tmp); 874 } else { // NOLINTNEXTLINE(readability-braces-around-statements) 875 auto *pTmp = reinterpret_cast<T *>(&int64Val); 876 res = *pTmp; 877 } 878 if (!littleEndian) { 879 res = LittleEndianToBigEndian<T>(res); 880 } 881 } 882 FastSetTypeData(byteBeginOffset, byteEndOffset, res); 883} 884 885template<typename T> 886void BuiltinsArrayBuffer::FastSetValueInBufferForFloat(uint8_t *byteBeginOffset, 887 uint8_t *byteEndOffset, 888 double val, bool littleEndian) 889{ 890 ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be float type"); 891 auto data = static_cast<T>(val); 892 if (!std::isnan(val)) { 893 if (!littleEndian) { 894 if constexpr (std::is_same_v<T, float>) { 895 uint32_t res = base::bit_cast<uint32_t>(data); 896 data = base::bit_cast<T>(LittleEndianToBigEndian(res)); 897 } else if constexpr (std::is_same_v<T, double>) { 898 uint64_t res = base::bit_cast<uint64_t>(data); 899 data = base::bit_cast<T>(LittleEndianToBigEndian64Bit(res)); 900 } 901 } 902 } 903 FastSetTypeData(byteBeginOffset, byteEndOffset, data); 904} 905 906template<typename T> 907void BuiltinsArrayBuffer::FastSetValueInBufferForBigInt(JSThread *thread, 908 uint8_t *byteBeginOffset, 909 uint8_t *byteEndOffset, 910 double val, bool littleEndian) 911{ 912 ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t"); 913 T value = 0; 914 bool lossless = true; 915 916 JSHandle<JSTaggedValue> valHandle(thread, GetTaggedDouble(val)); 917 if constexpr(std::is_same_v<T, uint64_t>) { 918 BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast<uint64_t *>(&value), &lossless); 919 } else { 920 BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast<int64_t *>(&value), &lossless); 921 } 922 RETURN_IF_ABRUPT_COMPLETION(thread); 923 if (!littleEndian) { 924 value = LittleEndianToBigEndian64Bit<T>(value); 925 } 926 FastSetTypeData(byteBeginOffset, byteEndOffset, value); 927} 928 929JSTaggedValue BuiltinsArrayBuffer::TryFastSetValueInBuffer([[maybe_unused]] JSThread *thread, JSTaggedValue arrBuf, 930 uint32_t byteBeginOffset, uint32_t byteEndOffset, 931 DataViewType type, double val, bool littleEndian) 932{ 933 uint8_t *beginPointer = reinterpret_cast<uint8_t *>(GetDataPointFromBuffer(arrBuf, byteBeginOffset)); 934 uint8_t *endPointer = reinterpret_cast<uint8_t *>(GetDataPointFromBuffer(arrBuf, byteEndOffset)); 935 switch (type) { 936 case DataViewType::UINT8: 937 FastSetValueInBufferForByte<uint8_t>(beginPointer, endPointer, val); 938 break; 939 case DataViewType::UINT8_CLAMPED: 940 FastSetValueInBufferForUint8Clamped(beginPointer, endPointer, val); 941 break; 942 case DataViewType::INT8: 943 FastSetValueInBufferForByte<int8_t>(beginPointer, endPointer, val); 944 break; 945 case DataViewType::UINT16: 946 FastSetValueInBufferForInteger<uint16_t>(beginPointer, endPointer, val, littleEndian); 947 break; 948 case DataViewType::INT16: 949 FastSetValueInBufferForInteger<int16_t>(beginPointer, endPointer, val, littleEndian); 950 break; 951 case DataViewType::UINT32: 952 FastSetValueInBufferForInteger<uint32_t>(beginPointer, endPointer, val, littleEndian); 953 break; 954 case DataViewType::INT32: 955 FastSetValueInBufferForInteger<int32_t>(beginPointer, endPointer, val, littleEndian); 956 break; 957 case DataViewType::FLOAT32: 958 FastSetValueInBufferForFloat<float>(beginPointer, endPointer, val, littleEndian); 959 break; 960 case DataViewType::FLOAT64: 961 FastSetValueInBufferForFloat<double>(beginPointer, endPointer, val, littleEndian); 962 break; 963 case DataViewType::BIGINT64: 964 FastSetValueInBufferForBigInt<int64_t>(thread, beginPointer, endPointer, val, littleEndian); 965 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 966 break; 967 case DataViewType::BIGUINT64: 968 FastSetValueInBufferForBigInt<uint64_t>(thread, beginPointer, endPointer, val, littleEndian); 969 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 970 break; 971 default: 972 LOG_ECMA(FATAL) << "this branch is unreachable"; 973 UNREACHABLE(); 974 } 975 return JSTaggedValue::Undefined(); 976} 977} // namespace panda::ecmascript::builtins 978