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