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