• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_CONTAINERS_CONTAINERS_BUFFER_H
17 #define ECMASCRIPT_CONTAINERS_CONTAINERS_BUFFER_H
18 
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/ecma_runtime_call_info.h"
21 
22 namespace panda::ecmascript::containers {
23 /**
24  * High performance container interface in jsapi.
25  * */
26 #define CONTAINER_BUFFER_CHECK(name)                                                                       \
27     JSHandle<JSTaggedValue> self = GetThis(argv);                                                          \
28     if (!self->IsJSAPIBuffer()) {                                                                          \
29         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget(thread).IsJSAPIBuffer()) {       \
30             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget(thread));      \
31         } else {                                                                                           \
32             JSTaggedValue error =                                                                          \
33                 ContainerError::BusinessError(thread, BIND_ERROR, "The " #name " method cannot be bound"); \
34             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());                   \
35         }                                                                                                  \
36     }
37 
38 #define CONTAINER_BUFFER_ACCESSORS(name)                                                               \
39     JSTaggedValue ContainersBuffer::Write##name##BE(EcmaRuntimeCallInfo *argv)                         \
40     {                                                                                                  \
41         ASSERT(argv != nullptr);                                                                       \
42         JSThread *thread = argv->GetThread();                                                          \
43         BUILTINS_API_TRACE(thread, Buffer, Write##name##BE);                                           \
44         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                          \
45         CONTAINER_BUFFER_CHECK(Write##name##BE)                                                        \
46         JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);                                           \
47         JSHandle<JSTaggedValue> offset = GetCallArg(argv, 1);                                          \
48         CHECK_NULL_OR_UNDEFINED(value);                                                                \
49         uint32_t offsetIndex = 0;                                                                      \
50         if (offset->IsNumber()) {                                                                      \
51             if (IsNegetiveNumber(offset)) {                                                            \
52                 std::ostringstream oss;                                                                \
53                 oss << "The value of \"offset\" is out of range. It must be >= 0. Received value is: " \
54                     << offset->GetNumber();                                                            \
55                 JSTaggedValue error =                                                                  \
56                     ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());  \
57                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());           \
58             }                                                                                          \
59             if (UNLIKELY(offset->IsDouble())) {                                                        \
60                 offsetIndex = static_cast<uint32_t>(offset->GetDouble());                              \
61             } else {                                                                                   \
62                 offsetIndex = static_cast<uint32_t>(offset->GetInt());                                 \
63             }                                                                                          \
64         }                                                                                              \
65         if (value->IsUndefined() || value->IsNull()) {                                                 \
66             return JSTaggedValue(offsetIndex);                                                         \
67         }                                                                                              \
68         JSHandle<JSAPIFastBuffer> buffer = JSHandle<JSAPIFastBuffer>::Cast(self);                      \
69         auto ret = JSAPIFastBuffer::Write##name(thread, buffer, value, offsetIndex, false);            \
70         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                                 \
71         return ret;                                                                                    \
72     }                                                                                                  \
73     JSTaggedValue ContainersBuffer::Write##name##LE(EcmaRuntimeCallInfo *argv)                         \
74     {                                                                                                  \
75         ASSERT(argv != nullptr);                                                                       \
76         JSThread *thread = argv->GetThread();                                                          \
77         BUILTINS_API_TRACE(thread, Buffer, Write##name##LE);                                           \
78         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                          \
79         CONTAINER_BUFFER_CHECK(Write##name##LE)                                                        \
80         JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);                                           \
81         JSHandle<JSTaggedValue> offset = GetCallArg(argv, 1);                                          \
82         CHECK_NULL_OR_UNDEFINED(value);                                                                \
83         uint32_t offsetIndex = 0;                                                                      \
84         if (offset->IsNumber()) {                                                                      \
85             if (IsNegetiveNumber(offset)) {                                                            \
86                 std::ostringstream oss;                                                                \
87                 oss << "The value of \"offset\" is out of range. It must be >= 0. Received value is: " \
88                     << offset->GetNumber();                                                            \
89                 JSTaggedValue error =                                                                  \
90                     ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());  \
91                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());           \
92             }                                                                                          \
93             if (UNLIKELY(offset->IsDouble())) {                                                        \
94                 offsetIndex = static_cast<uint32_t>(offset->GetDouble());                              \
95             } else {                                                                                   \
96                 offsetIndex = static_cast<uint32_t>(offset->GetInt());                                 \
97             }                                                                                          \
98         }                                                                                              \
99         if (value->IsUndefined() || value->IsNull()) {                                                 \
100             return JSTaggedValue(offsetIndex);                                                         \
101         }                                                                                              \
102         JSHandle<JSAPIFastBuffer> buffer = JSHandle<JSAPIFastBuffer>::Cast(self);                      \
103         auto ret = JSAPIFastBuffer::Write##name(thread, buffer, value, offsetIndex, true);             \
104         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                                 \
105         return ret;                                                                                    \
106     }                                                                                                  \
107     JSTaggedValue ContainersBuffer::Read##name##BE(EcmaRuntimeCallInfo *argv)                          \
108     {                                                                                                  \
109         ASSERT(argv != nullptr);                                                                       \
110         JSThread *thread = argv->GetThread();                                                          \
111         BUILTINS_API_TRACE(thread, Buffer, Read##name##BE);                                            \
112         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                          \
113         CONTAINER_BUFFER_CHECK(Read##name##BE)                                                         \
114         JSHandle<JSTaggedValue> offset = GetCallArg(argv, 0);                                          \
115         uint32_t offsetIndex = 0;                                                                      \
116         if (offset->IsNumber()) {                                                                      \
117             if (IsNegetiveNumber(offset)) {                                                            \
118                 std::ostringstream oss;                                                                \
119                 oss << "The value of \"offset\" is out of range. It must be >= 0. Received value is: " \
120                     << offset->GetNumber();                                                            \
121                 JSTaggedValue error =                                                                  \
122                     ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());  \
123                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());           \
124             }                                                                                          \
125             if (UNLIKELY(offset->IsDouble())) {                                                        \
126                 offsetIndex = static_cast<uint32_t>(offset->GetDouble());                              \
127             } else {                                                                                   \
128                 offsetIndex = static_cast<uint32_t>(offset->GetInt());                                 \
129             }                                                                                          \
130         }                                                                                              \
131         JSHandle<JSAPIFastBuffer> buffer = JSHandle<JSAPIFastBuffer>::Cast(self);                      \
132         auto ret = JSAPIFastBuffer::Read##name(thread, buffer, offsetIndex, false);                    \
133         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                                 \
134         return ret;                                                                                    \
135     }                                                                                                  \
136     JSTaggedValue ContainersBuffer::Read##name##LE(EcmaRuntimeCallInfo *argv)                          \
137     {                                                                                                  \
138         ASSERT(argv != nullptr);                                                                       \
139         JSThread *thread = argv->GetThread();                                                          \
140         BUILTINS_API_TRACE(thread, Buffer, Read##name##LE);                                            \
141         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                          \
142         CONTAINER_BUFFER_CHECK(Read##name##LE)                                                         \
143         JSHandle<JSTaggedValue> offset = GetCallArg(argv, 0);                                          \
144         uint32_t offsetIndex = 0;                                                                      \
145         if (offset->IsNumber()) {                                                                      \
146             if (IsNegetiveNumber(offset)) {                                                            \
147                 std::ostringstream oss;                                                                \
148                 oss << "The value of \"offset\" is out of range. It must be >= 0. Received value is: " \
149                     << offset->GetNumber();                                                            \
150                 JSTaggedValue error =                                                                  \
151                     ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());  \
152                 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());           \
153             }                                                                                          \
154             if (UNLIKELY(offset->IsDouble())) {                                                        \
155                 offsetIndex = static_cast<uint32_t>(offset->GetDouble());                              \
156             } else {                                                                                   \
157                 offsetIndex = static_cast<uint32_t>(offset->GetInt());                                 \
158             }                                                                                          \
159         }                                                                                              \
160         JSHandle<JSAPIFastBuffer> buffer = JSHandle<JSAPIFastBuffer>::Cast(self);                      \
161         auto ret = JSAPIFastBuffer::Read##name(thread, buffer, offsetIndex, true);                     \
162         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                                 \
163         return ret;                                                                                    \
164     }
165 
166 #define CONTAINER_FASTBUFFER_PROTOTYPE_FUNCTIONS(V)     \
167     V("toString", ToString, 3, INVALID)                 \
168     V("write", Write, 3, INVALID)                       \
169     V("writeUIntBE", WriteUIntBE, 3, INVALID)           \
170     V("writeUIntLE", WriteUIntLE, 3, INVALID)           \
171     V("writeIntBE", WriteIntBE, 3, INVALID)             \
172     V("writeIntLE", WriteIntLE, 3, INVALID)             \
173     V("writeUInt8", WriteUInt8, 2, INVALID)             \
174     V("writeUInt16BE", WriteUInt16BE, 2, INVALID)       \
175     V("writeUInt16LE", WriteUInt16LE, 2, INVALID)       \
176     V("writeUInt32BE", WriteUInt32BE, 2, INVALID)       \
177     V("writeUInt32LE", WriteUInt32LE, 2, INVALID)       \
178     V("writeInt8", WriteInt8, 2, INVALID)               \
179     V("writeInt16BE", WriteInt16BE, 2, INVALID)         \
180     V("writeInt16LE", WriteInt16LE, 2, INVALID)         \
181     V("writeInt32BE", WriteInt32BE, 2, INVALID)         \
182     V("writeInt32LE", WriteInt32LE, 2, INVALID)         \
183     V("writeFloatBE", WriteFloat32BE, 2, INVALID)       \
184     V("writeDoubleBE", WriteFloat64BE, 2, INVALID)      \
185     V("writeFloatLE", WriteFloat32LE, 2, INVALID)       \
186     V("writeDoubleLE", WriteFloat64LE, 2, INVALID)      \
187     V("writeBigUInt64BE", WriteBigUInt64BE, 2, INVALID) \
188     V("writeBigUInt64LE", WriteBigUInt64LE, 2, INVALID) \
189     V("writeBigInt64BE", WriteBigInt64BE, 2, INVALID)   \
190     V("writeBigInt64LE", WriteBigInt64LE, 2, INVALID)   \
191     V("readUIntBE", ReadUIntBE, 2, INVALID)             \
192     V("readUIntLE", ReadUIntLE, 2, INVALID)             \
193     V("readIntBE", ReadIntBE, 2, INVALID)               \
194     V("readIntLE", ReadIntLE, 2, INVALID)               \
195     V("readInt8", ReadInt8, 1, INVALID)                 \
196     V("readUInt8", ReadUInt8, 1, INVALID)               \
197     V("readUInt16BE", ReadUInt16BE, 1, INVALID)         \
198     V("readUInt16LE", ReadUInt16LE, 1, INVALID)         \
199     V("readUInt32BE", ReadUInt32BE, 1, INVALID)         \
200     V("readUInt32LE", ReadUInt32LE, 1, INVALID)         \
201     V("readInt16BE", ReadInt16BE, 1, INVALID)           \
202     V("readInt16LE", ReadInt16LE, 1, INVALID)           \
203     V("readInt32BE", ReadInt32BE, 1, INVALID)           \
204     V("readInt32LE", ReadInt32LE, 1, INVALID)           \
205     V("readFloatBE", ReadFloat32BE, 1, INVALID)         \
206     V("readFloatLE", ReadFloat32LE, 1, INVALID)         \
207     V("readDoubleBE", ReadFloat64BE, 1, INVALID)        \
208     V("readDoubleLE", ReadFloat64LE, 1, INVALID)        \
209     V("readBigUInt64BE", ReadBigUInt64BE, 1, INVALID)   \
210     V("readBigUInt64LE", ReadBigUInt64LE, 1, INVALID)   \
211     V("readBigInt64BE", ReadBigInt64BE, 1, INVALID)     \
212     V("readBigInt64LE", ReadBigInt64LE, 1, INVALID)     \
213     V("entries", Entries, 0, INVALID)                   \
214     V("keys", Keys, 0, INVALID)                         \
215     V("values", Values, 0, INVALID)                     \
216     V("copy", Copy, 4, INVALID)                         \
217     V("fill", Fill, 4, INVALID)                         \
218     V("includes", Includes, 3, INVALID)                 \
219     V("indexOf", IndexOf, 3, INVALID)                   \
220     V("lastIndexOf", LastIndexOf, 3, INVALID)           \
221     V("compare", Compare, 5, INVALID)                   \
222     V("equals", Equals, 1, INVALID)
223 
224 class ContainersBuffer : public base::BuiltinsBase {
225 public:
226     static JSTaggedValue BufferConstructor(EcmaRuntimeCallInfo *argv);
227     static JSTaggedValue Fill(EcmaRuntimeCallInfo *argv);
228     static JSTaggedValue Copy(EcmaRuntimeCallInfo *argv);
229     static JSTaggedValue Includes(EcmaRuntimeCallInfo *argv);
230     static JSTaggedValue Compare(EcmaRuntimeCallInfo *argv);
231     static JSTaggedValue Equals(EcmaRuntimeCallInfo *argv);
232     static JSTaggedValue IndexOf(EcmaRuntimeCallInfo *argv);
233     static JSTaggedValue LastIndexOf(EcmaRuntimeCallInfo *argv);
234     static JSTaggedValue Write(EcmaRuntimeCallInfo *argv);
235     static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
236     static JSTaggedValue WriteIntBE(EcmaRuntimeCallInfo *argv);
237     static JSTaggedValue WriteIntLE(EcmaRuntimeCallInfo *argv);
238     static JSTaggedValue WriteUIntBE(EcmaRuntimeCallInfo *argv);
239     static JSTaggedValue WriteUIntLE(EcmaRuntimeCallInfo *argv);
240     static JSTaggedValue ReadIntBE(EcmaRuntimeCallInfo *argv);
241     static JSTaggedValue ReadIntLE(EcmaRuntimeCallInfo *argv);
242     static JSTaggedValue ReadUIntBE(EcmaRuntimeCallInfo *argv);
243     static JSTaggedValue ReadUIntLE(EcmaRuntimeCallInfo *argv);
244     static JSTaggedValue WriteInt8(EcmaRuntimeCallInfo *argv);
245     static JSTaggedValue WriteUInt8(EcmaRuntimeCallInfo *argv);
246     static JSTaggedValue ReadUInt8(EcmaRuntimeCallInfo *argv);
247     static JSTaggedValue ReadInt8(EcmaRuntimeCallInfo *argv);
248 
249 #define DECL_CONTAINER_BUFFER_ACCESSORS(name)                        \
250     static JSTaggedValue Write##name##BE(EcmaRuntimeCallInfo *argv); \
251     static JSTaggedValue Write##name##LE(EcmaRuntimeCallInfo *argv); \
252     static JSTaggedValue Read##name##BE(EcmaRuntimeCallInfo *argv);  \
253     static JSTaggedValue Read##name##LE(EcmaRuntimeCallInfo *argv);
254     DECL_CONTAINER_BUFFER_ACCESSORS(UInt8)
255     DECL_CONTAINER_BUFFER_ACCESSORS(UInt16)
256     DECL_CONTAINER_BUFFER_ACCESSORS(UInt32)
257     DECL_CONTAINER_BUFFER_ACCESSORS(BigInt64)
258     DECL_CONTAINER_BUFFER_ACCESSORS(Int8)
259     DECL_CONTAINER_BUFFER_ACCESSORS(Int16)
260     DECL_CONTAINER_BUFFER_ACCESSORS(Int32)
261     DECL_CONTAINER_BUFFER_ACCESSORS(BigUInt64)
262     DECL_CONTAINER_BUFFER_ACCESSORS(Float32)
263     DECL_CONTAINER_BUFFER_ACCESSORS(Float64)
264 #undef DECL_CONTAINER_BUFFER_ACCESSORS
265 
266     static JSTaggedValue GetSize(EcmaRuntimeCallInfo *argv);
267     static JSTaggedValue GetByteOffset(EcmaRuntimeCallInfo *argv);
268     static JSTaggedValue GetArrayBuffer(EcmaRuntimeCallInfo *argv);
269     static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv);
270     static JSTaggedValue Keys(EcmaRuntimeCallInfo *argv);
271     static JSTaggedValue Values(EcmaRuntimeCallInfo *argv);
272 
273     // Excluding the constructor and '@@' internal properties.
GetFastBufferPrototypeFunctions()274     static Span<const base::BuiltinFunctionEntry> GetFastBufferPrototypeFunctions()
275     {
276         return Span<const base::BuiltinFunctionEntry>(FASTBUFFER_PROTOTYPE_FUNCTIONS);
277     }
278 
279 private:
280 #define CONTAINER_FASTBUFFER_FUNCTION_ENTRY(name, method, length, id) \
281     base::BuiltinFunctionEntry::Create(name, ContainersBuffer::method, length, BUILTINS_STUB_ID(id)),
282 
283     static constexpr std::array FASTBUFFER_PROTOTYPE_FUNCTIONS = {
284         CONTAINER_FASTBUFFER_PROTOTYPE_FUNCTIONS(CONTAINER_FASTBUFFER_FUNCTION_ENTRY)};
285 #undef CONTAINER_FASTBUFFER_FUNCTION_ENTRY
286 };
287 }  // namespace panda::ecmascript::containers
288 #endif  // ECMASCRIPT_CONTAINERS_CONTAINERS_BUFFER_H
289