1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/tagged_list.h"
17
18 #include "ecmascript/base/array_helper.h"
19 #include "ecmascript/containers/containers_errors.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_function.h"
22 #include "ecmascript/js_object-inl.h"
23
24 namespace panda::ecmascript {
25 template <typename Derived>
Create(const JSThread * thread,int numberOfNodes)26 JSHandle<Derived> TaggedList<Derived>::Create(const JSThread *thread, int numberOfNodes)
27 {
28 ASSERT_PRINT(numberOfNodes > 0, "size must be a non-negative integer");
29 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
30 int length = ELEMENTS_START_INDEX + Derived::ENTRY_SIZE + numberOfNodes * Derived::ENTRY_SIZE;
31 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(length);
32 auto taggedList = JSHandle<Derived>::Cast(taggedArray);
33 JSTaggedValue data = JSTaggedValue(ELEMENTS_START_INDEX);
34 taggedList->SetNumberOfNodes(thread, 0);
35 taggedList->SetNumberOfDeletedNodes(thread, 0);
36 taggedList->SetElement(thread, HEAD_TABLE_INDEX, data);
37 taggedList->SetElement(thread, TAIL_TABLE_INDEX, data);
38 taggedList->SetElement(thread, ELEMENTS_START_INDEX, JSTaggedValue::Hole());
39 taggedList->SetElement(thread, ELEMENTS_START_INDEX + NEXT_PTR_OFFSET, data);
40 return taggedList;
41 }
42
43 template <typename Derived>
CopyArray(const JSThread * thread,JSHandle<Derived> & taggedList)44 void TaggedList<Derived>::CopyArray(const JSThread *thread, JSHandle<Derived> &taggedList)
45 {
46 int deleteNodeNum = NumberOfDeletedNodes();
47 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
48 if (deleteNodeNum == 0) {
49 int capacity = GetCapacityFromTaggedArray();
50 for (int i = 0; i < capacity; i++) {
51 value.Update(GetElement(thread, i));
52 taggedList->SetElement(thread, i, value.GetTaggedValue());
53 }
54 taggedList->SetNumberOfDeletedNodes(thread, NumberOfDeletedNodes());
55 return;
56 }
57
58 int actualNodeNum = NumberOfNodes();
59 int tailTableIndex = ELEMENTS_START_INDEX + actualNodeNum * Derived::ENTRY_SIZE;
60 int nextTailIndex = ELEMENTS_START_INDEX + Derived::ENTRY_SIZE;
61 JSTaggedValue data = JSTaggedValue(ELEMENTS_START_INDEX);
62 taggedList->SetNumberOfNodes(thread, actualNodeNum);
63 taggedList->SetNumberOfDeletedNodes(thread, 0);
64 taggedList->SetElement(thread, HEAD_TABLE_INDEX, data);
65 taggedList->SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(tailTableIndex));
66 taggedList->SetElement(thread, ELEMENTS_START_INDEX, JSTaggedValue::Hole());
67 taggedList->SetElement(thread, ELEMENTS_START_INDEX + NEXT_PTR_OFFSET, JSTaggedValue(nextTailIndex));
68 if constexpr (std::is_same_v<TaggedDoubleList, Derived>) {
69 taggedList->SetElement(thread, ELEMENTS_START_INDEX + PREV_PTR_OFFSET, JSTaggedValue(tailTableIndex));
70 }
71 int srcDataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + NEXT_PTR_OFFSET).GetInt();
72 for (int i = 0; i < actualNodeNum; i++) {
73 int index = nextTailIndex + i * Derived::ENTRY_SIZE;
74 taggedList->SetElement(thread, index, GetElement(thread, srcDataIndex));
75 taggedList->SetElement(thread, index + NEXT_PTR_OFFSET, JSTaggedValue(index + Derived::ENTRY_SIZE));
76 if constexpr (std::is_same_v<TaggedDoubleList, Derived>) {
77 taggedList->SetElement(thread, index + PREV_PTR_OFFSET,
78 JSTaggedValue(ELEMENTS_START_INDEX + i * Derived::ENTRY_SIZE));
79 }
80 srcDataIndex = GetPrimitiveElement(srcDataIndex + NEXT_PTR_OFFSET).GetInt();
81 }
82 taggedList->SetElement(thread, tailTableIndex + NEXT_PTR_OFFSET, JSTaggedValue(ELEMENTS_START_INDEX));
83 }
84
85 template <typename Derived>
GrowCapacity(const JSThread * thread,const JSHandle<Derived> & taggedList)86 JSHandle<Derived> TaggedList<Derived>::GrowCapacity(const JSThread *thread, const JSHandle<Derived> &taggedList)
87 {
88 int actualNodeNum = taggedList->NumberOfNodes();
89 int deleteNodeNum = taggedList->NumberOfDeletedNodes();
90 int needCapacity = actualNodeNum + 1;
91 int taggedArrayLength = taggedList->GetCapacityFromTaggedArray();
92 int actualArrayCapacity = (taggedArrayLength - ELEMENTS_START_INDEX - (deleteNodeNum + 1) * Derived::ENTRY_SIZE);
93 if (needCapacity * Derived::ENTRY_SIZE < actualArrayCapacity) {
94 return taggedList;
95 }
96 uint32_t length = static_cast<uint32_t>(actualNodeNum);
97 uint32_t newCapacity = length + (length >> 1UL);
98 JSHandle<Derived> list = Create(thread, newCapacity < DEFAULT_ARRAY_LENGHT ? DEFAULT_ARRAY_LENGHT : newCapacity);
99 taggedList->CopyArray(thread, list);
100 return list;
101 }
102
103 template <typename Derived>
Clear(const JSThread * thread)104 void TaggedList<Derived>::Clear(const JSThread *thread)
105 {
106 int numberOfNodes = NumberOfNodes();
107 int dataIndex = ELEMENTS_START_INDEX;
108 for (int i = 0; i < numberOfNodes; i++) {
109 dataIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
110 SetElement(thread, dataIndex, JSTaggedValue::Hole());
111 }
112 JSTaggedValue data = JSTaggedValue(ELEMENTS_START_INDEX);
113 SetNumberOfNodes(thread, 0);
114 SetNumberOfDeletedNodes(thread, 0);
115 SetElement(thread, HEAD_TABLE_INDEX, data);
116 SetElement(thread, TAIL_TABLE_INDEX, data);
117 SetElement(thread, ELEMENTS_START_INDEX, JSTaggedValue::Hole());
118 SetElement(thread, ELEMENTS_START_INDEX + NEXT_PTR_OFFSET, data);
119 }
120
121 template <typename Derived>
TaggedListToArray(const JSThread * thread,const JSHandle<Derived> & list)122 JSTaggedValue TaggedList<Derived>::TaggedListToArray(const JSThread *thread, const JSHandle<Derived> &list)
123 {
124 uint32_t numberOfNodes = static_cast<uint32_t>(list->NumberOfNodes());
125
126 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
127 JSHandle<JSArray> array = factory->NewJSArray();
128 array->SetArrayLength(thread, numberOfNodes);
129 if (numberOfNodes == 0) {
130 return array.GetTaggedValue();
131 }
132 JSHandle<TaggedArray> newElements = factory->ConvertListToArray(thread, list, numberOfNodes);
133 array->SetElements(thread, newElements);
134 return array.GetTaggedValue();
135 }
136
137 template <typename Derived>
OwnKeys(JSThread * thread,const JSHandle<Derived> & list)138 JSHandle<TaggedArray> TaggedList<Derived>::OwnKeys(JSThread *thread, const JSHandle<Derived> &list)
139 {
140 uint32_t length = static_cast<uint32_t>(list->NumberOfNodes());
141 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
142 JSHandle<TaggedArray> keys = factory->NewTaggedArray(length);
143
144 for (uint32_t i = 0; i < length; i++) {
145 auto key = base::NumberHelper::IntToEcmaString(thread, i);
146 keys->Set(thread, i, key);
147 }
148 return keys;
149 }
150
151 template<typename Derived>
FindIndexByElement(const JSThread * thread,const JSTaggedValue & element)152 int TaggedList<Derived>::FindIndexByElement(const JSThread *thread, const JSTaggedValue &element)
153 {
154 int dataIndex = ELEMENTS_START_INDEX;
155 int nextDataIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
156 int nodeSum = 0;
157 while (nextDataIndex != ELEMENTS_START_INDEX) {
158 dataIndex = nextDataIndex;
159 JSTaggedValue data = GetElement(thread, dataIndex);
160 nextDataIndex = GetPrimitiveElement(nextDataIndex + NEXT_PTR_OFFSET).GetInt();
161 if (JSTaggedValue::SameValue(thread, data, element)) {
162 return nodeSum;
163 }
164 nodeSum++;
165 }
166 return -1;
167 }
168
169 template<typename Derived>
FindLastIndexByElement(const JSThread * thread,const JSTaggedValue & element)170 int TaggedList<Derived>::FindLastIndexByElement(const JSThread *thread, const JSTaggedValue &element)
171 {
172 int dataIndex = ELEMENTS_START_INDEX;
173 int nextIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
174 int nodeSum = 0;
175 int lastIndex = -1;
176 while (nextIndex != ELEMENTS_START_INDEX) {
177 dataIndex = nextIndex;
178 JSTaggedValue data = GetElement(thread, dataIndex);
179 if (JSTaggedValue::SameValue(thread, data, element)) {
180 lastIndex = nodeSum;
181 }
182 nextIndex = GetPrimitiveElement(nextIndex + NEXT_PTR_OFFSET).GetInt();
183 nodeSum++;
184 }
185 return lastIndex;
186 }
187
188 template<typename Derived>
FindDataIndexByNodeIndex(int index) const189 int TaggedList<Derived>::FindDataIndexByNodeIndex(int index) const
190 {
191 int dataIndex = ELEMENTS_START_INDEX;
192 int nextIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
193 int nodeSum = 0;
194 while (nextIndex != ELEMENTS_START_INDEX) {
195 dataIndex = nextIndex;
196 if (nodeSum == index) {
197 return dataIndex;
198 }
199 nextIndex = GetPrimitiveElement(nextIndex + NEXT_PTR_OFFSET).GetInt();
200 nodeSum++;
201 }
202 return -1;
203 }
204
205 template<typename Derived>
MapNodeIndexToDataIndex(std::vector<int> & nodeIndexMapToDataIndex,int length)206 void TaggedList<Derived>::MapNodeIndexToDataIndex(std::vector<int> &nodeIndexMapToDataIndex, int length)
207 {
208 int i = 0;
209 int nextIndex = ELEMENTS_START_INDEX;
210 while (i < length) {
211 nextIndex = GetPrimitiveElement(nextIndex + NEXT_PTR_OFFSET).GetInt();
212 nodeIndexMapToDataIndex[i] = nextIndex;
213 i++;
214 }
215 }
216
217 template<typename Derived>
RemoveNode(JSThread * thread,int prevDataIndex)218 void TaggedList<Derived>::RemoveNode(JSThread *thread, int prevDataIndex)
219 {
220 int tailTableIndex = GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
221 if (tailTableIndex != GetElement(thread, HEAD_TABLE_INDEX).GetInt()) {
222 int dataIndex = GetPrimitiveElement(prevDataIndex + NEXT_PTR_OFFSET).GetInt();
223 int nextDataIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
224 if (dataIndex == tailTableIndex) {
225 SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(prevDataIndex));
226 }
227 if constexpr (std::is_same_v<TaggedDoubleList, Derived>) {
228 SetElement(thread, nextDataIndex + PREV_PTR_OFFSET, JSTaggedValue(prevDataIndex));
229 }
230 SetElement(thread, dataIndex, JSTaggedValue::Hole());
231 SetElement(thread, prevDataIndex + NEXT_PTR_OFFSET, JSTaggedValue(nextDataIndex));
232 SetNumberOfNodes(thread, NumberOfNodes() - 1);
233 SetNumberOfDeletedNodes(thread, NumberOfDeletedNodes() + 1);
234 }
235 }
236
237 template<typename Derived>
FindPrevNodeByIndex(int index) const238 int TaggedList<Derived>::FindPrevNodeByIndex(int index) const
239 {
240 int prevDataIndex = ELEMENTS_START_INDEX;
241 int nodeSum = 0;
242 int len = GetPrimitiveElement(NUMBER_OF_NODE_INDEX).GetInt();
243 while (nodeSum <= len) {
244 if (nodeSum == index) {
245 return prevDataIndex;
246 }
247 prevDataIndex = GetPrimitiveElement(prevDataIndex + NEXT_PTR_OFFSET).GetInt();
248 nodeSum++;
249 }
250 return -1;
251 }
252
253 template<typename Derived>
FindPrevNodeByValue(const JSThread * thread,const JSTaggedValue & element)254 int TaggedList<Derived>::FindPrevNodeByValue(const JSThread *thread, const JSTaggedValue &element)
255 {
256 int dataIndex = ELEMENTS_START_INDEX;
257 int nodeSum = 0;
258 int len = GetPrimitiveElement(NUMBER_OF_NODE_INDEX).GetInt();
259 while (nodeSum <= len) {
260 int nextDataIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
261 JSTaggedValue data = GetElement(thread, nextDataIndex);
262 if (JSTaggedValue::SameValue(thread, data, element)) {
263 return dataIndex;
264 }
265 dataIndex = nextDataIndex;
266 nodeSum++;
267 }
268 return -1;
269 }
270
271 template<typename Derived>
FindElementByIndex(const JSThread * thread,int index) const272 JSTaggedValue TaggedList<Derived>::FindElementByIndex(const JSThread *thread, int index) const
273 {
274 int dataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + NEXT_PTR_OFFSET).GetInt();
275 int nodeSum = 0;
276 while (dataIndex != ELEMENTS_START_INDEX) {
277 if (nodeSum == index) {
278 return GetElement(thread, dataIndex);
279 }
280 dataIndex = GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
281 nodeSum++;
282 }
283 return JSTaggedValue::Undefined();
284 }
285
286 template<typename Derived>
FindElementByDataIndex(const JSThread * thread,int dataindex) const287 std::pair<int, JSTaggedValue> TaggedList<Derived>::FindElementByDataIndex(const JSThread *thread, int dataindex) const
288 {
289 int targetDataIndex = GetPrimitiveElement(dataindex + NEXT_PTR_OFFSET).GetInt();
290 JSTaggedValue value = GetElement(thread, targetDataIndex);
291 while (value.IsHole() && targetDataIndex != ELEMENTS_START_INDEX) {
292 targetDataIndex = GetPrimitiveElement(targetDataIndex + NEXT_PTR_OFFSET).GetInt();
293 value = GetElement(thread, targetDataIndex);
294 }
295 if (targetDataIndex == ELEMENTS_START_INDEX) {
296 return std::make_pair(-1, JSTaggedValue::Undefined());
297 }
298 return std::make_pair(targetDataIndex, value);
299 }
300
301 template<typename Derived>
RemoveByIndex(JSThread * thread,const int & index)302 JSTaggedValue TaggedList<Derived>::RemoveByIndex(JSThread *thread, const int &index)
303 {
304 int prevDataIndex = FindPrevNodeByIndex(index);
305 int curDataIndex = GetPrimitiveElement(prevDataIndex + NEXT_PTR_OFFSET).GetInt();
306 JSTaggedValue data = GetElement(thread, curDataIndex);
307 RemoveNode(thread, prevDataIndex);
308 return data;
309 }
310
311 // TaggedSingleList
Create(const JSThread * thread,int numberOfElements)312 JSTaggedValue TaggedSingleList::Create(const JSThread *thread, int numberOfElements)
313 {
314 return TaggedList<TaggedSingleList>::Create(thread, numberOfElements).GetTaggedValue();
315 }
316
Add(const JSThread * thread,const JSHandle<TaggedSingleList> & taggedList,const JSHandle<JSTaggedValue> & value)317 JSTaggedValue TaggedSingleList::Add(const JSThread *thread, const JSHandle<TaggedSingleList> &taggedList,
318 const JSHandle<JSTaggedValue> &value)
319 {
320 int prevDataIndex = taggedList->GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
321 return TaggedSingleList::AddNode(thread, taggedList, value, -1, prevDataIndex);
322 }
323
ConvertToArray(const JSThread * thread,const JSHandle<TaggedSingleList> & taggedList)324 JSTaggedValue TaggedSingleList::ConvertToArray(const JSThread *thread, const JSHandle<TaggedSingleList> &taggedList)
325 {
326 return JSTaggedValue(TaggedList<TaggedSingleList>::TaggedListToArray(thread, taggedList));
327 }
328
Insert(JSThread * thread,const JSHandle<TaggedSingleList> & taggedList,const JSHandle<JSTaggedValue> & value,const int index)329 JSTaggedValue TaggedSingleList::Insert(JSThread *thread, const JSHandle<TaggedSingleList> &taggedList,
330 const JSHandle<JSTaggedValue> &value, const int index)
331 {
332 int tailIndex = taggedList->GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
333 int prevDataIndex = (index == -1) ? tailIndex : taggedList->FindPrevNodeByIndex(index);
334 return TaggedSingleList::AddNode(thread, taggedList, value, index, prevDataIndex);
335 }
336
AddNode(const JSThread * thread,const JSHandle<TaggedSingleList> & taggedList,const JSHandle<JSTaggedValue> & value,const int index,int prevDataIndex)337 JSTaggedValue TaggedSingleList::AddNode(const JSThread *thread, const JSHandle<TaggedSingleList> &taggedList,
338 const JSHandle<JSTaggedValue> &value, const int index, int prevDataIndex)
339 {
340 JSHandle<TaggedSingleList> list = GrowCapacity(thread, taggedList);
341 int deleteNodeLength = list->NumberOfDeletedNodes();
342 int nodeLength = list->NumberOfNodes();
343 int finalDataIndex = ELEMENTS_START_INDEX + (nodeLength + 1 + deleteNodeLength) * TaggedSingleList::ENTRY_SIZE;
344
345 if (taggedList != list) {
346 if (index == -1) {
347 prevDataIndex = list->GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
348 } else {
349 prevDataIndex = list->FindPrevNodeByIndex(index);
350 }
351 }
352
353 list->InsertNode(thread, value, prevDataIndex, finalDataIndex);
354 if (index == -1 || nodeLength == index) {
355 list->SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(finalDataIndex));
356 }
357 return list.GetTaggedValue();
358 }
359
InsertNode(const JSThread * thread,const JSHandle<JSTaggedValue> & value,const int prevDataIndex,const int finalDataIndex)360 void TaggedSingleList::InsertNode(const JSThread *thread, const JSHandle<JSTaggedValue> &value, const int prevDataIndex,
361 const int finalDataIndex)
362 {
363 int prevNextIndex = prevDataIndex + NEXT_PTR_OFFSET;
364 int nextDataIndex = GetPrimitiveElement(prevNextIndex).GetInt();
365 SetElement(thread, prevNextIndex, JSTaggedValue(finalDataIndex));
366 SetElement(thread, finalDataIndex, value.GetTaggedValue());
367 SetElement(thread, finalDataIndex + 1, JSTaggedValue(nextDataIndex));
368 SetNumberOfNodes(thread, NumberOfNodes() + 1);
369 }
370
Has(const JSThread * thread,const JSTaggedValue & element)371 bool TaggedSingleList::Has(const JSThread *thread, const JSTaggedValue &element)
372 {
373 int dataIndex = FindIndexByElement(thread, element);
374 return dataIndex != -1;
375 }
376
IsEmpty() const377 bool TaggedSingleList::IsEmpty() const
378 {
379 return NumberOfNodes() == 0;
380 }
381
Get(const JSThread * thread,const int index)382 JSTaggedValue TaggedSingleList::Get(const JSThread *thread, const int index)
383 {
384 return FindElementByIndex(thread, index);
385 }
386
GetByDataIndex(const JSThread * thread,const int dataIndex)387 std::pair<int, JSTaggedValue> TaggedSingleList::GetByDataIndex(const JSThread *thread, const int dataIndex)
388 {
389 return FindElementByDataIndex(thread, dataIndex);
390 }
391
GetIndexOf(const JSThread * thread,const JSTaggedValue & element)392 int TaggedSingleList::GetIndexOf(const JSThread *thread, const JSTaggedValue &element)
393 {
394 return FindIndexByElement(thread, element);
395 }
396
GetLastIndexOf(const JSThread * thread,const JSTaggedValue & element)397 int TaggedSingleList::GetLastIndexOf(const JSThread *thread, const JSTaggedValue &element)
398 {
399 return FindLastIndexByElement(thread, element);
400 }
401
Set(JSThread * thread,const JSHandle<TaggedSingleList> & taggedList,const int index,const JSHandle<JSTaggedValue> & value)402 JSTaggedValue TaggedSingleList::Set(JSThread *thread, const JSHandle<TaggedSingleList> &taggedList,
403 const int index, const JSHandle<JSTaggedValue> &value)
404 {
405 int dataIndex = taggedList->FindDataIndexByNodeIndex(index);
406 if (dataIndex == -1) {
407 return taggedList.GetTaggedValue();
408 }
409 taggedList->SetElement(thread, dataIndex, value.GetTaggedValue());
410 return taggedList.GetTaggedValue();
411 }
412
ReplaceAllElements(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg,const JSHandle<TaggedSingleList> & taggedList)413 JSTaggedValue TaggedSingleList::ReplaceAllElements(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
414 const JSHandle<JSTaggedValue> &callbackFn,
415 const JSHandle<JSTaggedValue> &thisArg,
416 const JSHandle<TaggedSingleList> &taggedList)
417 {
418 int length = taggedList->NumberOfNodes();
419 int dataIndex = ELEMENTS_START_INDEX;
420 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
421 for (int k = 0; k < length; k++) {
422 dataIndex = taggedList->GetNextDataIndex(dataIndex);
423 JSTaggedValue kValue = taggedList->GetElement(thread, dataIndex);
424 JSTaggedValue key = JSTaggedValue(k);
425 EcmaRuntimeCallInfo *info =
426 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3:three args
427 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
428 info->SetCallArg(kValue, key, thisHandle.GetTaggedValue());
429 JSTaggedValue funcResult = JSFunction::Call(info);
430 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
431 JSHandle<JSTaggedValue> funcResultValue = JSHandle<JSTaggedValue>(thread, funcResult);
432 TaggedSingleList::Set(thread, taggedList, k, funcResultValue);
433 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
434 }
435 return JSTaggedValue::Undefined();
436 }
437
Sort(JSThread * thread,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<TaggedSingleList> & taggedList)438 JSTaggedValue TaggedSingleList::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &callbackFn,
439 const JSHandle<TaggedSingleList> &taggedList)
440 {
441 const int length = taggedList->NumberOfNodes();
442 const int minSortLength = 2;
443 if (length < minSortLength) {
444 return JSTaggedValue::Undefined();
445 }
446 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
447 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
448 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
449 // create index map
450 std::vector<int> nodeIndexMapToDataIndex(length, 0);
451 taggedList->MapNodeIndexToDataIndex(nodeIndexMapToDataIndex, length);
452
453 int beginIndex = 0;
454 int endIndex = 0;
455 int middleIndex = 0;
456 double compareResult = 0;
457 for (int i = 1; i < length; i++) {
458 beginIndex = 0;
459 endIndex = i;
460 presentValue.Update(taggedList->GetElement(thread, nodeIndexMapToDataIndex[i]));
461 while (beginIndex < endIndex) {
462 middleIndex = (beginIndex + endIndex) / 2; // 2 : half
463 middleValue.Update(taggedList->GetElement(thread, nodeIndexMapToDataIndex[middleIndex]));
464 compareResult = base::ArrayHelper::SortCompare(thread, callbackFn, middleValue, presentValue);
465 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
466 if (compareResult > 0) {
467 endIndex = middleIndex;
468 } else {
469 beginIndex = middleIndex + 1;
470 }
471 }
472
473 if (endIndex < i) {
474 for (int j = i; j > endIndex; j--) {
475 previousValue.Update(taggedList->GetElement(thread, nodeIndexMapToDataIndex[j - 1]));
476 taggedList->SetElement(thread, nodeIndexMapToDataIndex[j], previousValue.GetTaggedValue());
477 }
478 taggedList->SetElement(thread, nodeIndexMapToDataIndex[endIndex], presentValue.GetTaggedValue());
479 }
480 }
481
482 return JSTaggedValue::Undefined();
483 }
484
GetSubList(JSThread * thread,const JSHandle<TaggedSingleList> & taggedList,const int fromIndex,const int toIndex,const JSHandle<TaggedSingleList> & subList)485 void TaggedSingleList::GetSubList(JSThread *thread, const JSHandle<TaggedSingleList> &taggedList,
486 const int fromIndex, const int toIndex,
487 const JSHandle<TaggedSingleList> &subList)
488 {
489 int fromDataIndex = -1;
490 int toDataIndex = -1;
491 int dataIndex = taggedList->GetPrimitiveElement(ELEMENTS_START_INDEX + NEXT_PTR_OFFSET).GetInt();
492 int nodeSum = 0;
493 while (dataIndex != ELEMENTS_START_INDEX) {
494 if (nodeSum == fromIndex) {
495 fromDataIndex = dataIndex;
496 }
497 dataIndex = taggedList->GetPrimitiveElement(dataIndex + NEXT_PTR_OFFSET).GetInt();
498 nodeSum++;
499 if (nodeSum == toIndex) {
500 toDataIndex = dataIndex;
501 break;
502 }
503 }
504
505 int preDataIndex = ELEMENTS_START_INDEX;
506 JSMutableHandle<JSTaggedValue> dataHandle(thread, JSTaggedValue::Undefined());
507 int curDataIndex = preDataIndex;
508 while (fromDataIndex != toDataIndex) {
509 curDataIndex += TaggedSingleList::ENTRY_SIZE;
510 dataHandle.Update(taggedList->GetElement(thread, fromDataIndex));
511 subList->SetElement(thread, preDataIndex + NEXT_PTR_OFFSET, JSTaggedValue(curDataIndex));
512 subList->SetElement(thread, curDataIndex, dataHandle.GetTaggedValue());
513 preDataIndex = curDataIndex;
514 fromDataIndex = taggedList->GetPrimitiveElement(fromDataIndex + NEXT_PTR_OFFSET).GetInt();
515 }
516 subList->SetElement(thread, curDataIndex + NEXT_PTR_OFFSET, JSTaggedValue(ELEMENTS_START_INDEX));
517 subList->SetElement(thread, HEAD_TABLE_INDEX, JSTaggedValue(ELEMENTS_START_INDEX));
518 subList->SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(curDataIndex));
519 subList->SetNumberOfNodes(thread, toIndex - fromIndex);
520 subList->SetNumberOfDeletedNodes(thread, 0);
521 }
522
Equal(const JSThread * thread,const JSHandle<TaggedSingleList> & compareList)523 JSTaggedValue TaggedSingleList::Equal(const JSThread *thread, const JSHandle<TaggedSingleList> &compareList)
524 {
525 int compareListLength = compareList->NumberOfNodes();
526 if (compareListLength != NumberOfNodes()) {
527 return JSTaggedValue::False();
528 }
529 int nodeSum = 0;
530 int compareNode = ELEMENTS_START_INDEX;
531 int valueNode = ELEMENTS_START_INDEX;
532 while (nodeSum < compareListLength) {
533 compareNode = compareList->GetNextDataIndex(compareNode);
534 valueNode = GetNextDataIndex(valueNode);
535 JSTaggedValue compareValue = compareList->GetElement(thread, compareNode);
536 JSTaggedValue value = GetElement(thread, valueNode);
537 if (!JSTaggedValue::SameValue(thread, compareValue, value)) {
538 return JSTaggedValue::False();
539 }
540 nodeSum++;
541 }
542 return JSTaggedValue::True();
543 }
544
Clear(const JSThread * thread)545 void TaggedSingleList::Clear(const JSThread *thread)
546 {
547 TaggedList<TaggedSingleList>::Clear(thread);
548 }
549
RemoveByIndex(JSThread * thread,const int & index)550 JSTaggedValue TaggedSingleList::RemoveByIndex(JSThread *thread, const int &index)
551 {
552 return TaggedList<TaggedSingleList>::RemoveByIndex(thread, index);
553 }
554
Remove(JSThread * thread,const JSTaggedValue & element)555 JSTaggedValue TaggedSingleList::Remove(JSThread *thread, const JSTaggedValue &element)
556 {
557 int prevDataIndex = FindPrevNodeByValue(thread, element);
558 if (prevDataIndex == -1) {
559 return JSTaggedValue::False();
560 }
561 RemoveNode(thread, prevDataIndex);
562 return JSTaggedValue::True();
563 }
564
OwnKeys(JSThread * thread,const JSHandle<TaggedSingleList> & taggedList)565 JSHandle<TaggedArray> TaggedSingleList::OwnKeys(JSThread *thread, const JSHandle<TaggedSingleList> &taggedList)
566 {
567 return TaggedList<TaggedSingleList>::OwnKeys(thread, taggedList);
568 }
569
SortByNodeOrder(const JSThread * thread,const JSHandle<TaggedSingleList> & taggedList)570 JSTaggedValue TaggedSingleList::SortByNodeOrder(const JSThread *thread, const JSHandle<TaggedSingleList> &taggedList)
571 {
572 int actualNodeNum = taggedList->NumberOfNodes();
573 int nextDataIndex = taggedList->GetPrimitiveElement(ELEMENTS_START_INDEX + NEXT_PTR_OFFSET).GetInt();
574 uint32_t length = static_cast<uint32_t>(actualNodeNum);
575 JSHandle<TaggedSingleList> list = TaggedList<TaggedSingleList>::Create(
576 thread, length < DEFAULT_ARRAY_LENGHT ? DEFAULT_ARRAY_LENGHT : length);
577
578 int tailTableIndex = ELEMENTS_START_INDEX + actualNodeNum * TaggedSingleList::ENTRY_SIZE;
579 int nextTailIndex = ELEMENTS_START_INDEX + TaggedSingleList::ENTRY_SIZE;
580 list->SetNumberOfNodes(thread, actualNodeNum);
581 list->SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(tailTableIndex));
582 list->SetElement(thread, ELEMENTS_START_INDEX, JSTaggedValue::Hole());
583 list->SetElement(thread, ELEMENTS_START_INDEX + NEXT_PTR_OFFSET, JSTaggedValue(nextTailIndex));
584
585 for (int i = 0; i < actualNodeNum; ++i) {
586 int curDataIndex = ELEMENTS_START_INDEX + (i + 1) * TaggedSingleList::ENTRY_SIZE;
587 list->SetElement(thread, curDataIndex, taggedList->GetElement(thread, nextDataIndex));
588 list->SetElement(thread, curDataIndex + NEXT_PTR_OFFSET,
589 JSTaggedValue(curDataIndex + TaggedSingleList::ENTRY_SIZE));
590 nextDataIndex = taggedList->GetPrimitiveElement(nextDataIndex + NEXT_PTR_OFFSET).GetInt();
591 }
592 list->SetElement(thread, tailTableIndex + NEXT_PTR_OFFSET, JSTaggedValue(ELEMENTS_START_INDEX));
593 return list.GetTaggedValue();
594 }
595
596 // TaggedDoubleList
Create(const JSThread * thread,int numberOfElements)597 JSTaggedValue TaggedDoubleList::Create(const JSThread *thread, int numberOfElements)
598 {
599 JSHandle<TaggedDoubleList> taggedList = TaggedList<TaggedDoubleList>::Create(thread, numberOfElements);
600 taggedList->SetElement(thread, ELEMENTS_START_INDEX + PREV_PTR_OFFSET, JSTaggedValue(ELEMENTS_START_INDEX));
601 return taggedList.GetTaggedValue();
602 }
603
Add(const JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSHandle<JSTaggedValue> & value)604 JSTaggedValue TaggedDoubleList::Add(const JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
605 const JSHandle<JSTaggedValue> &value)
606 {
607 int prevDataIndex = taggedList->GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
608 return TaggedDoubleList::AddNode(thread, taggedList, value, -1, prevDataIndex);
609 }
610
AddFirst(const JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSHandle<JSTaggedValue> & value)611 JSTaggedValue TaggedDoubleList::AddFirst(const JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
612 const JSHandle<JSTaggedValue> &value)
613 {
614 int prevDataIndex = taggedList->FindPrevNodeByIndex(0);
615 return TaggedDoubleList::AddNode(thread, taggedList, value, 0, prevDataIndex);
616 }
617
ConvertToArray(const JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList)618 JSTaggedValue TaggedDoubleList::ConvertToArray(const JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList)
619 {
620 return JSTaggedValue(TaggedList<TaggedDoubleList>::TaggedListToArray(thread, taggedList));
621 }
622
Insert(JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSHandle<JSTaggedValue> & value,const int index)623 JSTaggedValue TaggedDoubleList::Insert(JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
624 const JSHandle<JSTaggedValue> &value, const int index)
625 {
626 int prevDataIndex = taggedList->GetPrevNode(index);
627 return TaggedDoubleList::AddNode(thread, taggedList, value, index, prevDataIndex);
628 }
629
AddNode(const JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSHandle<JSTaggedValue> & value,const int index,int prevDataIndex)630 JSTaggedValue TaggedDoubleList::AddNode(const JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
631 const JSHandle<JSTaggedValue> &value, const int index, int prevDataIndex)
632 {
633 JSHandle<TaggedDoubleList> list = GrowCapacity(thread, taggedList);
634 int deleteNodeLength = list->NumberOfDeletedNodes();
635 int nodeLength = list->NumberOfNodes();
636 int finalDataIndex = ELEMENTS_START_INDEX + (nodeLength + 1 + deleteNodeLength) * TaggedDoubleList::ENTRY_SIZE;
637
638 if (taggedList != list) {
639 if (index == -1) {
640 prevDataIndex = list->GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
641 } else if (index == 0) {
642 prevDataIndex = list->FindPrevNodeByIndex(0);
643 } else {
644 prevDataIndex = list->GetPrevNode(index);
645 }
646 }
647
648 list->InsertNode(thread, value, prevDataIndex, finalDataIndex);
649 if (index == -1 || nodeLength == index) {
650 list->SetElement(thread, TAIL_TABLE_INDEX, JSTaggedValue(finalDataIndex));
651 }
652 return list.GetTaggedValue();
653 }
654
InsertNode(const JSThread * thread,const JSHandle<JSTaggedValue> & value,const int prevDataIndex,const int finalDataIndex)655 void TaggedDoubleList::InsertNode(const JSThread *thread, const JSHandle<JSTaggedValue> &value, const int prevDataIndex,
656 const int finalDataIndex)
657 {
658 int prevNextIndex = prevDataIndex + NEXT_PTR_OFFSET;
659 int nextDataIndex = GetPrimitiveElement(prevNextIndex).GetInt();
660 int nextPrevIndex = nextDataIndex + PREV_PTR_OFFSET;
661 SetElement(thread, prevNextIndex, JSTaggedValue(finalDataIndex));
662 SetElement(thread, nextPrevIndex, JSTaggedValue(finalDataIndex));
663 SetElement(thread, finalDataIndex, value.GetTaggedValue());
664 SetElement(thread, finalDataIndex + NEXT_PTR_OFFSET, JSTaggedValue(nextDataIndex));
665 SetElement(thread, finalDataIndex + PREV_PTR_OFFSET, JSTaggedValue(prevDataIndex));
666 SetNumberOfNodes(thread, NumberOfNodes() + 1);
667 }
668
Has(const JSThread * thread,const JSTaggedValue & element)669 bool TaggedDoubleList::Has(const JSThread *thread, const JSTaggedValue &element)
670 {
671 int dataIndex = FindIndexByElement(thread, element);
672 return dataIndex != -1;
673 }
674
Get(const JSThread * thread,const int index)675 JSTaggedValue TaggedDoubleList::Get(const JSThread *thread, const int index)
676 {
677 int len = NumberOfNodes();
678 // 2 : 2 MEANS the half
679 if (len / 2 > index) {
680 return FindElementByIndex(thread, index);
681 } else {
682 return FindElementByIndexAtLast(thread, index);
683 }
684 }
685
GetByDataIndex(const JSThread * thread,const int dataIndex)686 std::pair<int, JSTaggedValue> TaggedDoubleList::GetByDataIndex(const JSThread *thread, const int dataIndex)
687 {
688 return FindElementByDataIndex(thread, dataIndex);
689 }
690
GetPrevNode(const int index)691 int TaggedDoubleList::GetPrevNode(const int index)
692 {
693 int len = NumberOfNodes();
694 // When index < (len / 2), search doubleList from the beginning
695 if ((len / 2) > index) {
696 return FindPrevNodeByIndex(index);
697 } else {
698 int leftNodeLen = len - 1 - index;
699 // When insert at last
700 if (leftNodeLen == -1) {
701 return GetPrimitiveElement(TAIL_TABLE_INDEX).GetInt();
702 }
703 // when index >= (len / 2), search doubleList from the end
704 return FindPrevNodeByIndexAtLast(leftNodeLen);
705 }
706 }
707
GetIndexOf(const JSThread * thread,const JSTaggedValue & element)708 int TaggedDoubleList::GetIndexOf(const JSThread *thread, const JSTaggedValue &element)
709 {
710 return FindIndexByElement(thread, element);
711 }
712
GetLastIndexOf(const JSThread * thread,const JSTaggedValue & element)713 int TaggedDoubleList::GetLastIndexOf(const JSThread *thread, const JSTaggedValue &element)
714 {
715 return FindLastIndexByElement(thread, element);
716 }
717
Set(JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const int index,const JSHandle<JSTaggedValue> & value)718 JSTaggedValue TaggedDoubleList::Set(JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList, const int index,
719 const JSHandle<JSTaggedValue> &value)
720 {
721 int nodeLength = taggedList->NumberOfNodes();
722 if (index < 0 || index >= nodeLength) {
723 JSTaggedValue error =
724 containers::ContainerError::BusinessError(thread, containers::ErrorFlag::RANGE_ERROR,
725 "The value of index is out of range");
726 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
727 }
728 int dataIndex = taggedList->FindDataIndexByNodeIndex(index);
729 if (dataIndex == -1) {
730 JSTaggedValue error =
731 containers::ContainerError::BusinessError(thread, containers::ErrorFlag::RANGE_ERROR,
732 "The value of index is out of range");
733 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
734 }
735 taggedList->SetElement(thread, dataIndex, value.GetTaggedValue());
736 return taggedList.GetTaggedValue();
737 }
738
Clear(const JSThread * thread)739 void TaggedDoubleList::Clear(const JSThread *thread)
740 {
741 TaggedList<TaggedDoubleList>::Clear(thread);
742 SetElement(thread, ELEMENTS_START_INDEX + PREV_PTR_OFFSET, JSTaggedValue(ELEMENTS_START_INDEX));
743 }
744
RemoveFirst(JSThread * thread)745 JSTaggedValue TaggedDoubleList::RemoveFirst(JSThread *thread)
746 {
747 int firstDataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + NEXT_PTR_OFFSET).GetInt();
748 JSTaggedValue firstData = GetElement(thread, firstDataIndex);
749 RemoveNode(thread, ELEMENTS_START_INDEX);
750 return firstData;
751 }
752
RemoveLast(JSThread * thread)753 JSTaggedValue TaggedDoubleList::RemoveLast(JSThread *thread)
754 {
755 int lastDataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + 2).GetInt();
756 int prevDataIndex = GetPrimitiveElement(lastDataIndex + 2).GetInt();
757 JSTaggedValue lastData = GetElement(thread, lastDataIndex);
758 RemoveNode(thread, prevDataIndex);
759 return lastData;
760 }
761
RemoveByIndex(JSThread * thread,const int & index)762 JSTaggedValue TaggedDoubleList::RemoveByIndex(JSThread *thread, const int &index)
763 {
764 int prevDataIndex = GetPrevNode(index);
765 int curDataIndex = GetPrimitiveElement(prevDataIndex + NEXT_PTR_OFFSET).GetInt();
766 JSTaggedValue data = GetElement(thread, curDataIndex);
767 RemoveNode(thread, prevDataIndex);
768 return data;
769 }
770
Remove(JSThread * thread,const JSTaggedValue & element)771 JSTaggedValue TaggedDoubleList::Remove(JSThread *thread, const JSTaggedValue &element)
772 {
773 int prevDataIndex = FindPrevNodeByValue(thread, element);
774 if (prevDataIndex == -1) {
775 return JSTaggedValue::False();
776 }
777 RemoveNode(thread, prevDataIndex);
778 return JSTaggedValue::True();
779 }
780
RemoveFirstFound(JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSTaggedValue & element)781 JSTaggedValue TaggedDoubleList::RemoveFirstFound(JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
782 const JSTaggedValue &element)
783 {
784 int prevDataIndex = taggedList->FindPrevNodeByValue(thread, element);
785 if (prevDataIndex == -1) {
786 JSTaggedValue error =
787 containers::ContainerError::BusinessError(thread, containers::ErrorFlag::IS_NOT_EXIST_ERROR,
788 "The element does not exist in this container");
789 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
790 }
791 taggedList->RemoveNode(thread, prevDataIndex);
792 return JSTaggedValue::True();
793 }
794
RemoveLastFound(JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList,const JSTaggedValue & element)795 JSTaggedValue TaggedDoubleList::RemoveLastFound(JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList,
796 const JSTaggedValue &element)
797 {
798 int prevDataIndex = taggedList->FindPrevNodeByValueAtLast(thread, element);
799 if (prevDataIndex == -1) {
800 JSTaggedValue error =
801 containers::ContainerError::BusinessError(thread, containers::ErrorFlag::IS_NOT_EXIST_ERROR,
802 "The element does not exist in this container");
803 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
804 }
805 taggedList->RemoveNode(thread, prevDataIndex);
806 return JSTaggedValue::True();
807 }
808
OwnKeys(JSThread * thread,const JSHandle<TaggedDoubleList> & taggedList)809 JSHandle<TaggedArray> TaggedDoubleList::OwnKeys(JSThread *thread, const JSHandle<TaggedDoubleList> &taggedList)
810 {
811 return TaggedList<TaggedDoubleList>::OwnKeys(thread, taggedList);
812 }
813
FindElementByIndexAtLast(const JSThread * thread,int index) const814 JSTaggedValue TaggedDoubleList::FindElementByIndexAtLast(const JSThread *thread, int index) const
815 {
816 int dataIndex = ELEMENTS_START_INDEX;
817 int preDataIndex = GetPrimitiveElement(dataIndex + PREV_PTR_OFFSET).GetInt();
818 int nodeSum = GetElement(thread, NUMBER_OF_NODE_INDEX).GetInt() - 1;
819 while (preDataIndex != ELEMENTS_START_INDEX) {
820 dataIndex = preDataIndex;
821 JSTaggedValue dataValue = GetElement(thread, dataIndex);
822 if (nodeSum == index) {
823 return dataValue;
824 }
825 preDataIndex = GetPrimitiveElement(preDataIndex + PREV_PTR_OFFSET).GetInt();
826 nodeSum--;
827 }
828 return JSTaggedValue::Undefined();
829 }
830
FindPrevNodeByIndexAtLast(const int index) const831 int TaggedDoubleList::FindPrevNodeByIndexAtLast(const int index) const
832 {
833 int prevDataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + PREV_PTR_OFFSET).GetInt();
834 int nodeSum = 0;
835 int len = GetPrimitiveElement(NUMBER_OF_NODE_INDEX).GetInt();
836 while (nodeSum <= len) {
837 int prePreDataIndex = GetPrimitiveElement(prevDataIndex + PREV_PTR_OFFSET).GetInt();
838 if (nodeSum == index) {
839 return prePreDataIndex;
840 }
841 prevDataIndex = prePreDataIndex;
842 nodeSum++;
843 }
844 return -1;
845 }
846
FindPrevNodeByValueAtLast(const JSThread * thread,const JSTaggedValue & element)847 int TaggedDoubleList::FindPrevNodeByValueAtLast(const JSThread *thread, const JSTaggedValue &element)
848 {
849 int prevDataIndex = GetPrimitiveElement(ELEMENTS_START_INDEX + PREV_PTR_OFFSET).GetInt();
850 int nodeSum = 0;
851 int len = GetPrimitiveElement(NUMBER_OF_NODE_INDEX).GetInt();
852 while (nodeSum <= len) {
853 int prePreDataIndex = GetPrimitiveElement(prevDataIndex + PREV_PTR_OFFSET).GetInt();
854 JSTaggedValue data = GetElement(thread, prevDataIndex);
855 if (JSTaggedValue::SameValue(thread, data, element)) {
856 return prePreDataIndex;
857 }
858 prevDataIndex = prePreDataIndex;
859 nodeSum++;
860 }
861 return -1;
862 }
863 } // namespace panda::ecmascript
864