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 #ifndef ECMASCRIPT_BUILTINS_BUILTINS_ARRAYBUFFER_H
17 #define ECMASCRIPT_BUILTINS_BUILTINS_ARRAYBUFFER_H
18 
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/base/number_helper.h"
21 #include "ecmascript/js_dataview.h"
22 #include "ecmascript/js_typed_array.h"
23 
24 // List of functions in ArrayBuffer, excluding the '@@' properties.
25 // V(name, func, length, stubIndex)
26 // where BuiltinsArrayBuffer::func refers to the native implementation of ArrayBuffer[name].
27 //       kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
28 #define BUILTIN_ARRAY_BUFFER_FUNCTIONS(V)                                           \
29     /* ArrayBuffer.isView ( arg ) */                                                \
30     V("isView", IsView, 1, ArrayBufferIsView)
31 
32 namespace panda::ecmascript::builtins {
33 static constexpr double NUMBER_HALF = 0.5;
34 static constexpr uint32_t BITS_MASK_FF = 0xFF;
35 static constexpr uint32_t BITS_EIGHT = 8;
36 static constexpr uint32_t BITS_TWENTY_FOUR = 24;
37 static constexpr uint32_t BITS_FORTY = 40;
38 static constexpr uint32_t BITS_FIFTY_SIX = 56;
39 static constexpr uint32_t BITS_THIRTY_ONE = 31;
40 using DataViewType = ecmascript::DataViewType;
41 union UnionType32 {
42     uint32_t uValue;
43     float value;
44 };
45 union UnionType64 {
46     uint64_t uValue;
47     double value;
48 };
49 class BuiltinsArrayBuffer : public base::BuiltinsBase {
50 public:
51     enum NumberSize : uint8_t {
52         UINT16 = 2, INT16 = 2, UINT32 = 4, INT32 = 4, FLOAT32 = 4, FLOAT64 = 8, BIGINT64 = 8, BIGUINT64 = 8
53     };
54 
55     // 24.1.2.1 ArrayBuffer(length)
56     static JSTaggedValue ArrayBufferConstructor(EcmaRuntimeCallInfo *argv);
57     // 24.1.3.1 ArrayBuffer.isView(arg)
58     static JSTaggedValue IsView(EcmaRuntimeCallInfo *argv);
59     // 24.1.3.3 get ArrayBuffer[@@species]
60     static JSTaggedValue Species(EcmaRuntimeCallInfo *argv);
61     // 24.1.4.1 get ArrayBuffer.prototype.byteLength
62     static JSTaggedValue GetByteLength(EcmaRuntimeCallInfo *argv);
63     // 24.1.4.3 ArrayBuffer.prototype.slice()
64     static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv);
65     // 24.1.1.2 IsDetachedBuffer(arrayBuffer)
66     static void IsDetachedBuffer(JSThread *thread, const JSHandle<JSTypedArray> &arrayBuffer);
67     static bool IsDetachedBuffer(JSTaggedValue arrayBuffer);
68     // 24.1.1.5 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isLittleEndian )
69     static JSTaggedValue GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex,
70                                             DataViewType type, bool littleEndian);
71     // 24.1.1.6 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isLittleEndian )
72     static JSTaggedValue SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex,
73                                           DataViewType type, const JSHandle<JSTaggedValue> &value, bool littleEndian);
74     // 24.1.1.4 CloneArrayBuffer( srcBuffer, srcByteOffset [, cloneConstructor] )
75     static JSTaggedValue CloneArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &srcBuffer,
76                                           uint32_t srcByteOffset, JSHandle<JSTaggedValue> constructor);
77     // 24.1.1.1 AllocateArrayBuffer(constructor, byteLength)
78     static JSTaggedValue AllocateArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget,
79                                              uint64_t byteLength);
80     // es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
81     static bool IsUnclampedIntegerElementType(DataViewType type);
82     // es12 25.1.2.7 IsBigIntElementType ( type )
83     static bool IsBigIntElementType(DataViewType type);
84 
85     // Excluding the '@@' internal properties
GetArrayBufferFunctions()86     static Span<const base::BuiltinFunctionEntry> GetArrayBufferFunctions()
87     {
88         return Span<const base::BuiltinFunctionEntry>(ARRAY_BUFFER_FUNCTIONS);
89     }
90 
91     static JSTaggedValue FastSetValueInBuffer(JSThread* thread, JSTaggedValue arrBuf, uint32_t byteIndex,
92                                               DataViewType type, double val, bool littleEndian);
93     static JSTaggedValue TryFastSetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteBeginOffset,
94                                                  uint32_t byteEndOffset, DataViewType type,
95                                                  double val, bool littleEndian);
96     template<typename T>
97     static void FastSetValueInBufferForByte(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
98                                             double val);
99     static void FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
100                                                     double val);
101     template<typename T>
102     static void FastSetValueInBufferForInteger(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
103                                                double val, bool littleEndian);
104     template<typename T>
105     static void FastSetValueInBufferForFloat(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
106                                              double val, bool littleEndian);
107     template<typename T>
108     static void FastSetValueInBufferForBigInt(JSThread *thread, uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
109                                               double val, bool littleEndian);
110     static JSTaggedValue SetValueInBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block,
111                                           DataViewType type, double val, bool littleEndian);
112     static JSTaggedValue GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block,
113                                             DataViewType type, bool littleEndian);
114     static void *GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset = 0);
115 
116 protected:
117     static constexpr uint64_t MAX_NATIVE_SIZE_LIMIT = 4_GB;
118     static constexpr char const *NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE = "total array buffer size out of limit(4_GB)";
119 
120 private:
121 #define BUILTIN_ARRAY_BUFFER_ENTRY(name, func, length, id)                                                             \
122     base::BuiltinFunctionEntry::Create((name), (BuiltinsArrayBuffer::func), (length), (kungfu::BuiltinsStubCSigns::id)),
123 
124     static constexpr std::array ARRAY_BUFFER_FUNCTIONS = {BUILTIN_ARRAY_BUFFER_FUNCTIONS(BUILTIN_ARRAY_BUFFER_ENTRY)};
125 #undef BUILTIN_ARRAY_BUFFER_ENTRY
126 
127     template <typename T>
128     static T LittleEndianToBigEndian(T liValue);
129     template<typename T>
130     static T LittleEndianToBigEndian64Bit(T liValue);
131 
132     template<typename T>
133     static void SetTypeData(uint8_t *block, T value, uint32_t index);
134 
135     template<typename T>
136     static void FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value);
137 
138     template<typename T, NumberSize size>
139     static JSTaggedValue GetValueFromBufferForInteger(uint8_t *block, uint32_t byteIndex, bool littleEndian);
140 
141     template<typename T, typename UnionType, NumberSize size>
142     static JSTaggedValue GetValueFromBufferForFloat(uint8_t *block, uint32_t byteIndex, bool littleEndian);
143     template<typename T1, typename T2>
144     static JSTaggedValue CommonConvert(T1 &value, T2 &res, bool littleEndian);
145     template<typename T, NumberSize size>
146     static JSTaggedValue GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block,
147                                                      uint32_t byteIndex, bool littleEndian);
148 
149     template<typename T>
150     static void SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex);
151 
152     static void SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex);
153 
154     template<typename T>
155     static void SetValueInBufferForInteger(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian);
156 
157     template<typename T>
158     static void SetValueInBufferForFloat(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian);
159 
160     template<typename T>
161     static void SetValueInBufferForBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &val,
162                                           JSHandle<JSTaggedValue> &arrBuf, uint32_t byteIndex, bool littleEndian);
163 
164     template<typename T>
165     static void SetValueInBufferForBigInt(JSThread *thread, double val,
166                                           uint8_t *block, uint32_t byteIndex, bool littleEndian);
167 
168     static JSTaggedValue TypedArrayToList(JSThread *thread, JSHandle<JSTypedArray>& items);
169 
170     friend class BuiltinsArray;
171     friend class BuiltinsSharedArray;
172 };
173 }  // namespace panda::ecmascript::builtins
174 
175 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_ARRAYBUFFER_H
176