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