• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(thread));
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(thread));
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(thread).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(thread).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(thread));
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(JSThread * thread,const JSTaggedValue & value) const135 bool JSAPIBitVector::Has(JSThread* thread, const JSTaggedValue& value) const
136 {
137     uint32_t length = GetSize();
138     if (length == 0) {
139         return false;
140     }
141     JSNativePointer* np = JSNativePointer::Cast(GetNativePointer(thread).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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread));
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(thread, 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(thread, *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