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