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