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