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