1 /*
2 * Copyright (c) 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/js_api/js_api_bitvector.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/global_env_constants-inl.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_array.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/js_handle.h"
24 #include "ecmascript/js_tagged_number.h"
25 #include "ecmascript/js_tagged_value.h"
26 #include "ecmascript/js_tagged_value-inl.h"
27 #include "ecmascript/tagged_array-inl.h"
28 #include "ecmascript/object_factory.h"
29 #include "ecmascript/shared_objects/concurrent_api_scope.h"
30
31 namespace panda::ecmascript {
32 using ContainerError = containers::ContainerError;
33 using ErrorFlag = containers::ErrorFlag;
Push(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value)34 bool JSAPIBitVector::Push(
35 JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, const JSHandle<JSTaggedValue>& value)
36 {
37 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
38 JSHandle<JSTaggedValue>::Cast(bitVector));
39 uint32_t length = static_cast<uint32_t>(bitVector->GetLength());
40 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
41 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
42 if ((length & TAGGED_VALUE_BIT_OFFSET) == 0) {
43 std::bitset<BIT_SET_LENGTH> increaseSet;
44 if (!value->IsZero()) {
45 increaseSet.set(0);
46 }
47 elements->push_back(increaseSet);
48 } else {
49 SetBit(elements, length, value.GetTaggedValue());
50 }
51 bitVector->SetLength(++length);
52 return true;
53 }
54
Pop(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector)55 JSTaggedValue JSAPIBitVector::Pop(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector)
56 {
57 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
58 JSHandle<JSTaggedValue>::Cast(bitVector));
59 if (bitVector->GetLength() <= 0) {
60 return JSTaggedValue::Undefined();
61 }
62 uint32_t lastIndex = static_cast<uint32_t>(bitVector->GetLength() - 1);
63 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
64 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
65
66 JSTaggedValue bit = GetBit(elements, lastIndex);
67 if ((lastIndex & TAGGED_VALUE_BIT_OFFSET) == 0) {
68 elements->pop_back();
69 } else {
70 SetBit(elements, lastIndex, JSTaggedValue(0));
71 }
72 bitVector->SetLength(lastIndex);
73 return bit;
74 }
75
Set(JSThread * thread,const uint32_t index,JSTaggedValue value)76 JSTaggedValue JSAPIBitVector::Set(JSThread* thread, const uint32_t index, JSTaggedValue value)
77 {
78 uint32_t length = static_cast<uint32_t>(GetLength());
79 if (index >= length) {
80 std::ostringstream oss;
81 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
82 << ". Received value is: " << index;
83 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
84 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
85 }
86 JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
87 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
88 SetBit(elements, index, value);
89 return JSTaggedValue::Undefined();
90 }
91
Get(JSThread * thread,const uint32_t index)92 JSTaggedValue JSAPIBitVector::Get(JSThread* thread, const uint32_t index)
93 {
94 uint32_t length = static_cast<uint32_t>(GetLength());
95 if (index >= length) {
96 std::ostringstream oss;
97 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
98 << ". Received value is: " << index;
99 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
100 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
101 }
102 JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
103 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
104 return GetBit(elements, index);
105 }
106
Has(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)107 bool JSAPIBitVector::Has(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
108 const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
109 {
110 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
111 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
112 int32_t length = bitVector->GetLength();
113 int32_t size = length > endIndex ? endIndex : length;
114 if (endIndex < 0 || endIndex > length) {
115 std::ostringstream oss;
116 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
117 << ". Received value is: " << endIndex;
118 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
119 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
120 }
121 if (startIndex < 0 || startIndex >= size) {
122 std::ostringstream oss;
123 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
124 << ". Received value is: " << startIndex;
125 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
126 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
127 }
128 if (length == 0) {
129 return false;
130 }
131 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
132 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
133 for (int index = startIndex; index <= endIndex; index++) {
134 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
135 uint32_t elementId = pair.first;
136 uint32_t bitId = pair.second;
137 if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
138 (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
139 return true;
140 }
141 }
142 return false;
143 }
144
Has(const JSTaggedValue & value) const145 bool JSAPIBitVector::Has(const JSTaggedValue& value) const
146 {
147 uint32_t length = GetSize();
148 if (length == 0) {
149 return false;
150 }
151 JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
152 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
153 for (uint32_t index = 0; index < length; index++) {
154 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
155 uint32_t elementId = pair.first;
156 uint32_t bitId = pair.second;
157 if ((value.IsZero() && (*elements)[elementId].test(bitId) == 0) ||
158 (!value.IsZero() && (*elements)[elementId].test(bitId) != 0)) {
159 return true;
160 }
161 }
162 return false;
163 }
164
SetBitsByRange(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)165 JSTaggedValue JSAPIBitVector::SetBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
166 const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
167 {
168 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
169 JSHandle<JSTaggedValue>::Cast(bitVector));
170 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
171 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
172 int32_t length = bitVector->GetLength();
173 int32_t size = length > endIndex ? endIndex : length;
174 if (endIndex < 0 || endIndex > length) {
175 std::ostringstream oss;
176 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
177 << ". Received value is: " << endIndex;
178 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
179 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
180 }
181 if (startIndex < 0 || startIndex >= size) {
182 std::ostringstream oss;
183 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
184 << ". Received value is: " << startIndex;
185 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
186 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
187 }
188
189 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
190 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
191 for (int32_t index = startIndex; index < endIndex; index++) {
192 SetBit(elements, index, value.GetTaggedValue());
193 }
194 return JSTaggedValue::Undefined();
195 }
196
GetBitsByRange(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)197 JSTaggedValue JSAPIBitVector::GetBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
198 const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
199 {
200 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
201 JSHandle<JSTaggedValue>::Cast(bitVector));
202 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
203 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
204 int32_t length = bitVector->GetLength();
205 int32_t size = length > endIndex ? endIndex : length;
206 if (endIndex < 0 || endIndex > length) {
207 std::ostringstream oss;
208 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
209 << ". Received value is: " << endIndex;
210 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
211 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
212 }
213 if (startIndex < 0 || startIndex >= size) {
214 std::ostringstream oss;
215 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
216 << ". Received value is: " << startIndex;
217 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
218 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
219 }
220 int32_t dstLength = endIndex - startIndex;
221 auto factory = thread->GetEcmaVM()->GetFactory();
222 JSHandle<JSNativePointer> srcNp(thread, bitVector->GetNativePointer());
223 auto srcElements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(srcNp->GetExternalPointer());
224
225 JSHandle<JSAPIBitVector> newBitVector = factory->NewJSAPIBitVector(dstLength);
226 JSHandle<JSNativePointer> dstNp(thread, newBitVector->GetNativePointer());
227 auto dstElements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(dstNp->GetExternalPointer());
228
229 for (int32_t index = 0; index < dstLength; index++) {
230 JSTaggedValue value = GetBit(srcElements, index + startIndex);
231 SetBit(dstElements, index, value);
232 }
233 newBitVector->SetLength(dstLength);
234 newBitVector->SetNativePointer(thread, dstNp);
235
236 return newBitVector.GetTaggedValue();
237 }
238
SetAllBits(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value)239 JSTaggedValue JSAPIBitVector::SetAllBits(
240 JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, const JSHandle<JSTaggedValue>& value)
241 {
242 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
243 JSHandle<JSTaggedValue>::Cast(bitVector));
244 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
245 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
246 int size = static_cast<int>(elements->size());
247 if (value->IsZero()) {
248 for (int index = 0; index < size; index++) {
249 (*elements)[index] = std::bitset<BIT_SET_LENGTH>(0);
250 }
251 } else {
252 for (int index = 0; index < size; index++) {
253 (*elements)[index] = std::bitset<BIT_SET_LENGTH>(UINT64_MAX);
254 }
255 }
256 return JSTaggedValue::Undefined();
257 }
258
GetBitCountByRange(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)259 JSTaggedValue JSAPIBitVector::GetBitCountByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
260 const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
261 {
262 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
263 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
264 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
265 int32_t length = bitVector->GetLength();
266 int32_t size = length > endIndex ? endIndex : length;
267 int32_t count = 0;
268 if (endIndex < 0 || endIndex > length) {
269 std::ostringstream oss;
270 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
271 << ". Received value is: " << endIndex;
272 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
273 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
274 }
275 if (startIndex < 0 || startIndex >= size) {
276 std::ostringstream oss;
277 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
278 << ". Received value is: " << startIndex;
279 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
280 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
281 }
282 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
283 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
284 for (int32_t index = startIndex; index < endIndex; index++) {
285 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
286 uint32_t elementId = pair.first;
287 uint32_t bitId = pair.second;
288 if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
289 (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
290 count++;
291 }
292 }
293 return JSTaggedValue(count);
294 }
295
GetIndexOf(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)296 int JSAPIBitVector::GetIndexOf(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
297 const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
298 {
299 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
300 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
301 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
302 int32_t length = bitVector->GetLength();
303 int32_t size = length > endIndex ? endIndex : length;
304 if (endIndex < 0 || endIndex > length) {
305 std::ostringstream oss;
306 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
307 << ". Received value is: " << endIndex;
308 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
309 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
310 }
311 if (startIndex < 0 || startIndex >= size) {
312 std::ostringstream oss;
313 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
314 << ". Received value is: " << startIndex;
315 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
316 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
317 }
318 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
319 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
320 for (int32_t index = startIndex; index < endIndex; index++) {
321 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
322 uint32_t elementId = pair.first;
323 uint32_t bitId = pair.second;
324 if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
325 (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
326 return index;
327 }
328 }
329 return -1;
330 }
331
GetLastIndexOf(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)332 int JSAPIBitVector::GetLastIndexOf(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
333 const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
334 {
335 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
336 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
337 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
338 int32_t length = bitVector->GetLength();
339 int32_t size = length > endIndex ? endIndex : length;
340 if (endIndex < 0 || endIndex > length) {
341 std::ostringstream oss;
342 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
343 << ". Received value is: " << endIndex;
344 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
345 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
346 }
347 if (startIndex < 0 || startIndex >= size) {
348 std::ostringstream oss;
349 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
350 << ". Received value is: " << startIndex;
351 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
352 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
353 }
354 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
355 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
356 for (int32_t index = endIndex - 1; index >= startIndex; index--) {
357 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
358 uint32_t elementId = pair.first;
359 uint32_t bitId = pair.second;
360 if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
361 (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
362 return index;
363 }
364 }
365 return -1;
366 }
367
FlipBitByIndex(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,int index)368 JSTaggedValue JSAPIBitVector::FlipBitByIndex(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, int index)
369 {
370 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
371 JSHandle<JSTaggedValue>::Cast(bitVector));
372 if (index >= bitVector->GetLength() || index < 0) {
373 std::ostringstream oss;
374 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (bitVector->GetLength() - 1)
375 << ". Received value is: " << index;
376 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
377 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
378 }
379
380 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
381 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
382
383 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
384 uint32_t elementId = pair.first;
385 uint32_t bitId = pair.second;
386 (*elements)[elementId].flip(bitId);
387 return JSTaggedValue::Undefined();
388 }
389
FlipBitsByRange(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,const JSHandle<JSTaggedValue> & start,const JSHandle<JSTaggedValue> & end)390 JSTaggedValue JSAPIBitVector::FlipBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
391 const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
392 {
393 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
394 JSHandle<JSTaggedValue>::Cast(bitVector));
395 int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
396 int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
397 int32_t length = bitVector->GetLength();
398 int32_t size = length > endIndex ? endIndex : length;
399 if (endIndex < 0 || endIndex > length) {
400 std::ostringstream oss;
401 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
402 << ". Received value is: " << endIndex;
403 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
404 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
405 }
406 if (startIndex < 0 || startIndex >= size) {
407 std::ostringstream oss;
408 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
409 << ". Received value is: " << startIndex;
410 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
411 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
412 }
413 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
414 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
415 for (int32_t index = startIndex; index < endIndex; index++) {
416 std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
417 uint32_t elementId = pair.first;
418 uint32_t bitId = pair.second;
419 (*elements)[elementId].flip(bitId);
420 }
421 return JSTaggedValue::Undefined();
422 }
423
Resize(JSThread * thread,const JSHandle<JSAPIBitVector> & bitVector,int newSize)424 void JSAPIBitVector::Resize(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, int newSize)
425 {
426 if (newSize < 0) {
427 std::ostringstream oss;
428 oss << "The value of \"length\" is out of range. It must be >= 0" << ". Received value is: " << newSize;
429 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
430 THROW_NEW_ERROR_AND_RETURN(thread, error);
431 }
432 [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
433 JSHandle<JSTaggedValue>::Cast(bitVector));
434 int length = bitVector->GetLength();
435 uint32_t elementsLength = static_cast<uint32_t>((length - 1) / BIT_SET_LENGTH + 1);
436 uint32_t newElementsLength = static_cast<uint32_t>((newSize - 1) / BIT_SET_LENGTH + 1);
437
438 JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
439 auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
440 if (elementsLength == newElementsLength && length < newSize) {
441 for (int32_t index = length; index < newSize; index++) {
442 SetBit(elements, index, JSTaggedValue(0));
443 }
444 } else if (elementsLength < newElementsLength) {
445 std::bitset<JSAPIBitVector::BIT_SET_LENGTH> initBitSet;
446 elements->resize(newElementsLength, initBitSet);
447 } else if (elementsLength > newElementsLength) {
448 elements->resize(newElementsLength);
449 }
450 bitVector->SetLength(newSize);
451 }
452
OwnKeys(JSThread * thread,const JSHandle<JSAPIBitVector> & obj)453 JSHandle<TaggedArray> JSAPIBitVector::OwnKeys(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
454 {
455 uint32_t numOfElements = static_cast<uint32_t>(obj->GetLength());
456 JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(numOfElements);
457
458 if (numOfElements > 0) {
459 for (uint32_t i = 0; i < numOfElements; ++i) {
460 auto key = base::NumberHelper::IntToEcmaString(thread, i);
461 keyArray->Set(thread, i, key);
462 }
463 }
464
465 return keyArray;
466 }
467
OwnEnumKeys(JSThread * thread,const JSHandle<JSAPIBitVector> & obj)468 JSHandle<TaggedArray> JSAPIBitVector::OwnEnumKeys(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
469 {
470 return OwnKeys(thread, obj);
471 }
472
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIBitVector> & obj,const JSHandle<JSTaggedValue> & key)473 bool JSAPIBitVector::GetOwnProperty(
474 JSThread* thread, const JSHandle<JSAPIBitVector>& obj, const JSHandle<JSTaggedValue>& key)
475 {
476 uint32_t index = 0;
477 if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
478 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
479 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
480 CString errorMsg = "The type of \"index\" can not obtain attributes of no-number type. Received value is: " +
481 ConvertToString(*result);
482 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
483 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
484 }
485
486 uint32_t length = static_cast<uint32_t>(obj->GetLength());
487 if (index >= length) {
488 std::ostringstream oss;
489 oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
490 << ". Received value is: " << index;
491 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
492 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
493 }
494
495 obj->Get(thread, index);
496 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
497 return true;
498 }
499
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIBitVector> & obj)500 JSTaggedValue JSAPIBitVector::GetIteratorObj(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
501 {
502 ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
503 JSHandle<JSAPIBitVectorIterator> iter(factory->NewJSAPIBitVectorIterator(obj));
504
505 return iter.GetTaggedValue();
506 }
507
GetProperty(JSThread * thread,const JSHandle<JSAPIBitVector> & obj,const JSHandle<JSTaggedValue> & key)508 OperationResult JSAPIBitVector::GetProperty(
509 JSThread* thread, const JSHandle<JSAPIBitVector>& obj, const JSHandle<JSTaggedValue>& key)
510 {
511 int length = obj->GetLength();
512 int index = key->GetInt();
513 if (index < 0 || index >= length) {
514 std::ostringstream oss;
515 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
516 << ". Received value is: " << index;
517 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
518 THROW_NEW_ERROR_AND_RETURN_VALUE(
519 thread, error, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
520 }
521
522 return OperationResult(thread, obj->Get(thread, index), PropertyMetaData(false));
523 }
SetProperty(JSThread * thread,const JSHandle<JSAPIBitVector> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)524 bool JSAPIBitVector::SetProperty(JSThread* thread, const JSHandle<JSAPIBitVector>& obj,
525 const JSHandle<JSTaggedValue>& key, const JSHandle<JSTaggedValue>& value)
526 {
527 int length = obj->GetLength();
528 int index = key->GetInt();
529 if (index < 0 || index >= length) {
530 return false;
531 }
532
533 obj->Set(thread, index, value.GetTaggedValue());
534 return true;
535 }
536
537 } // namespace panda::ecmascript
538