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