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