• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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