1 /*
2  * Copyright (c) 2022-2024 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 #ifndef ECMASCRIPT_TAGGED_TREE_H
17 #define ECMASCRIPT_TAGGED_TREE_H
18 
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_tagged_value.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/tagged_array-inl.h"
23 
24 namespace panda::ecmascript {
25 enum TreeColor : uint8_t { BLACK = 0, RED };
26 /**
27  * The tree layout is as follows:
28  * 1.array[0-4] is used to store common information, such as:
29  * +------------------------+-----------------------------+------------------------+------------+------------------+
30  * | the number of elements | the number of hole elements | the number of capacity | root index | compare function |
31  * +------------------------+-----------------------------+------------------------+------------+------------------+
32  * 2.array[5,5+capacity] is used to store node of tree, map and set store nodes in different formats respectively.
33  * */
34 template<typename Derived>
35 class TaggedTree : public TaggedArray {
36 public:
37     static constexpr int MIN_CAPACITY = 7;
38     static constexpr int NUMBER_OF_ELEMENTS_INDEX = 0;
39     static constexpr int NUMBER_OF_HOLE_ENTRIES_INDEX = 1;
40     static constexpr int CAPACITY_INDEX = 2;
41     static constexpr int ROOT_INDEX = 3;
42     static constexpr int COMPARE_FUNCTION_INDEX = 4;
43     static constexpr int ELEMENTS_START_INDEX = 5;
44     static constexpr int MIN_SHRINK_CAPACITY = 15;
45 
46     static JSHandle<Derived> Create(const JSThread *thread, int numberOfElements);
47 
48     static JSHandle<Derived> Insert(JSThread *thread, JSHandle<Derived> &tree, const JSHandle<JSTaggedValue> &key,
49                                     const JSHandle<JSTaggedValue> &value);
50 
51     static JSHandle<Derived> GrowCapacity(const JSThread *thread, JSHandle<Derived> &tree);
52 
ComputeCapacity(int oldCapacity)53     inline static int ComputeCapacity(int oldCapacity)
54     {
55         int capacity = (static_cast<uint32_t>(oldCapacity) << 1) + 1;
56         return (capacity > MIN_CAPACITY) ? capacity : MIN_CAPACITY;
57     }
58 
59     static void Remove(const JSThread *thread, const JSHandle<Derived> &tree, int entry);
60 
NumberOfElements() const61     inline uint32_t NumberOfElements() const
62     {
63         return Get(NUMBER_OF_ELEMENTS_INDEX).GetInt();
64     }
65 
NumberOfDeletedElements() const66     inline uint32_t NumberOfDeletedElements() const
67     {
68         return Get(NUMBER_OF_HOLE_ENTRIES_INDEX).GetInt();
69     }
70 
Capacity() const71     inline int Capacity() const
72     {
73         return Get(CAPACITY_INDEX).GetInt();
74     }
75 
GetKey(int entry) const76     inline JSTaggedValue GetKey(int entry) const
77     {
78         if (entry < 0) {
79             return JSTaggedValue::Hole();
80         }
81         int index = EntryToIndex(entry);
82         return GetElement(index);
83     }
84 
GetValue(int entry) const85     inline JSTaggedValue GetValue(int entry) const
86     {
87         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_VALUE_INDEX);
88         return GetElement(index);
89     }
90 
GetColor(int entry) const91     inline TreeColor GetColor(int entry) const
92     {
93         if (entry < 0) {
94             return TreeColor::BLACK;
95         }
96         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_COLOR_INDEX);
97         JSTaggedValue color = GetElement(index);
98         return color.GetInt() == TreeColor::RED ? TreeColor::RED : TreeColor::BLACK;
99     }
100 
SetCapacity(const JSThread *thread, int capacity)101     inline void SetCapacity(const JSThread *thread, int capacity)
102     {
103         Set(thread, CAPACITY_INDEX, JSTaggedValue(capacity));
104     }
105 
IsKey(JSTaggedValue key)106     inline static bool IsKey(JSTaggedValue key)
107     {
108         return !key.IsHole();
109     }
110 
SetNumberOfElements(const JSThread *thread, uint32_t num)111     inline void SetNumberOfElements(const JSThread *thread, uint32_t num)
112     {
113         Set(thread, NUMBER_OF_ELEMENTS_INDEX, JSTaggedValue(num));
114     }
115 
SetNumberOfDeletedElements(const JSThread *thread, int num)116     inline void SetNumberOfDeletedElements(const JSThread *thread, int num)
117     {
118         Set(thread, NUMBER_OF_HOLE_ENTRIES_INDEX, JSTaggedValue(num));
119     }
120 
SetRootEntries(const JSThread *thread, int num)121     inline void SetRootEntries(const JSThread *thread, int num)
122     {
123         Set(thread, ROOT_INDEX, JSTaggedValue(num));
124     }
125 
GetRootEntries() const126     inline int GetRootEntries() const
127     {
128         return Get(ROOT_INDEX).GetInt();
129     }
130 
131     static int FindEntry(JSThread *thread, const JSHandle<Derived> &tree, const JSHandle<JSTaggedValue> &key);
132 
133     static ComparisonResult EntryCompare(JSThread *thread, const JSHandle<JSTaggedValue> valueX,
134                                                 const JSHandle<JSTaggedValue> valueY, JSHandle<Derived> tree);
135 
SetKey(const JSThread *thread, uint32_t entry, JSTaggedValue key)136     inline void SetKey(const JSThread *thread, uint32_t entry, JSTaggedValue key)
137     {
138         int index = EntryToIndex(entry);
139         SetElement(thread, index, key);
140     }
141 
SetValue(const JSThread *thread, uint32_t entry, JSTaggedValue value)142     inline void SetValue(const JSThread *thread, uint32_t entry, JSTaggedValue value)
143     {
144         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_VALUE_INDEX);
145         SetElement(thread, index, value);
146     }
147 
SetCompare(const JSThread *thread, JSTaggedValue fn)148     inline void SetCompare(const JSThread *thread, JSTaggedValue fn)
149     {
150         Set(thread, COMPARE_FUNCTION_INDEX, fn);
151     }
152 
GetCompare() const153     inline JSTaggedValue GetCompare() const
154     {
155         return Get(COMPARE_FUNCTION_INDEX);
156     }
157 
GetMinimum(int entry) const158     inline int GetMinimum(int entry) const
159     {
160         JSTaggedValue child = GetLeftChild(entry);
161         while (!child.IsHole()) {
162             entry = child.GetInt();
163             child = GetLeftChild(entry);
164         }
165         return entry;
166     }
167 
GetMaximum(int entry) const168     inline int GetMaximum(int entry) const
169     {
170         JSTaggedValue child = GetRightChild(entry);
171         while (!child.IsHole()) {
172             entry = child.GetInt();
173             child = GetRightChild(entry);
174         }
175         return entry;
176     }
177 
GetParent(int entry) const178     inline int GetParent(int entry) const
179     {
180         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_PARENT_INDEX);
181         JSTaggedValue parent = GetElement(index);
182         return parent.GetInt();
183     }
184 
GetLeftChild(int parent) const185     inline JSTaggedValue GetLeftChild(int parent) const
186     {
187         if (parent < 0) {
188             return JSTaggedValue::Hole();
189         }
190         int index = static_cast<int>(EntryToIndex(parent) + Derived::ENTRY_LEFT_CHILD_INDEX);
191         return Get(index);
192     }
193 
GetRightChild(int parent) const194     inline JSTaggedValue GetRightChild(int parent) const
195     {
196         if (parent < 0) {
197             return JSTaggedValue::Hole();
198         }
199         int index = static_cast<int>(EntryToIndex(parent) + Derived::ENTRY_RIGHT_CHILD_INDEX);
200         return Get(index);
201     }
202 
GetLeftChildIndex(int parent) const203     inline int GetLeftChildIndex(int parent) const
204     {
205         if (parent < 0) {
206             return -1;
207         }
208         int index = static_cast<int>(EntryToIndex(parent) + Derived::ENTRY_LEFT_CHILD_INDEX);
209         JSTaggedValue child = Get(index);
210         return child.IsHole() ? -1 : child.GetInt();
211     }
212 
GetRightChildIndex(int parent) const213     inline int GetRightChildIndex(int parent) const
214     {
215         if (parent < 0) {
216             return -1;
217         }
218         int index = static_cast<int>(EntryToIndex(parent) + Derived::ENTRY_RIGHT_CHILD_INDEX);
219         JSTaggedValue child = Get(index);
220         return child.IsHole() ? -1 : child.GetInt();
221     }
222 
223 protected:
GetElement(int index) const224     inline JSTaggedValue GetElement(int index) const
225     {
226         ASSERT(index >= 0 && index < static_cast<int>(GetLength()));
227         return Get(index);
228     }
229 
230     // get root
GetRootKey() const231     inline JSTaggedValue GetRootKey() const
232     {
233         return GetKey(GetRootEntries());
234     }
235 
EntryToIndex(uint32_t entry) const236     inline int EntryToIndex(uint32_t entry) const
237     {
238         return ELEMENTS_START_INDEX + entry * (Derived::ENTRY_SIZE);
239     }
240 
SetElement(const JSThread *thread, uint32_t index, JSTaggedValue element)241     inline void SetElement(const JSThread *thread, uint32_t index, JSTaggedValue element)
242     {
243         ASSERT(index >= 0 && index < GetLength());
244         Set(thread, index, element);
245     }
246 
SetParent(const JSThread *thread, int entry, JSTaggedValue value)247     inline void SetParent(const JSThread *thread, int entry, JSTaggedValue value)
248     {
249         if (entry < 0) {
250             return;
251         }
252         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_PARENT_INDEX);
253         SetElement(thread, index, value);
254     }
255 
SetRoot(JSThread *thread, int index, JSTaggedValue key, JSTaggedValue value)256     inline void SetRoot(JSThread *thread, int index, JSTaggedValue key, JSTaggedValue value)
257     {
258         SetKey(thread, 0, key);
259         SetValue(thread, 0, value);
260         SetParent(thread, 0, JSTaggedValue(-1));
261         SetColor(thread, 0, TreeColor::BLACK);
262         SetRootEntries(thread, index);
263     }
264 
SetColor(const JSThread *thread, int entry, TreeColor color)265     inline void SetColor(const JSThread *thread, int entry, TreeColor color)
266     {
267         if (entry >= 0) {
268             int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_COLOR_INDEX);
269             SetElement(thread, index, JSTaggedValue(static_cast<int>(color)));
270         }
271     }
272 
InsertLeftEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry, JSTaggedValue key, JSTaggedValue value)273     inline void InsertLeftEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry, JSTaggedValue key,
274                                 JSTaggedValue value)
275     {
276         SetKey(thread, entry, key);
277         SetValue(thread, entry, value);
278         SetColor(thread, entry, TreeColor::RED);
279         SetParent(thread, entry, JSTaggedValue(parentIndex));
280         SetLeftChild(thread, parentIndex, JSTaggedValue(entry));
281     }
282 
InsertRightEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry, JSTaggedValue key, JSTaggedValue value)283     inline void InsertRightEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry, JSTaggedValue key,
284                                  JSTaggedValue value)
285     {
286         SetKey(thread, entry, key);
287         SetValue(thread, entry, value);
288         SetColor(thread, entry, TreeColor::RED);
289         SetParent(thread, entry, JSTaggedValue(parentIndex));
290         SetRightChild(thread, parentIndex, JSTaggedValue(entry));
291     }
292 
293     void InsertRebalance(const JSThread *thread, int index);
294     void DeleteRebalance(const JSThread *thread, int index);
295 
IsValidIndex(int entry) const296     inline bool IsValidIndex(int entry) const
297     {
298         return entry != GetRootEntries() && !GetKey(entry).IsHole();
299     }
300 
GetLeftBrother(int entry) const301     inline int GetLeftBrother(int entry) const
302     {
303         JSTaggedValue child = GetRightChild(GetParent(entry));
304         return child.IsHole() ? -1 : child.GetInt();
305     }
306 
GetRightBrother(int entry) const307     inline int GetRightBrother(int entry) const
308     {
309         JSTaggedValue child = GetLeftChild(GetParent(entry));
310         return child.IsHole() ? -1 : child.GetInt();
311     }
312 
IsLeft(int entry) const313     inline bool IsLeft(int entry) const
314     {
315         JSTaggedValue child = GetLeftChild(GetParent(entry));
316         return child.IsHole() ? false : (child.GetInt() == entry);
317     }
318 
IsRight(int entry) const319     inline bool IsRight(int entry) const
320     {
321         JSTaggedValue child = GetRightChild(GetParent(entry));
322         return child.IsHole() ? false : (child.GetInt() == entry);
323     }
324 
325     int GetPreDecessor(int entry) const;
326     int GetSuccessor(int entry) const;
327 
SetLeftChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)328     inline void SetLeftChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)
329     {
330         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_LEFT_CHILD_INDEX);
331         SetElement(thread, index, value);
332     }
SetRightChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)333     inline void SetRightChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)
334     {
335         int index = static_cast<int>(EntryToIndex(entry) + Derived::ENTRY_RIGHT_CHILD_INDEX);
336         SetElement(thread, index, value);
337     }
338 
339     void LeftRotate(const JSThread *thread, int index);
340     void RightRotate(const JSThread *thread, int index);
341 
342     static JSHandle<Derived> AdjustTaggedTree(const JSThread *thread, const JSHandle<Derived> &tree, int len);
OrdinayEntryCompare(JSThread *thread, const JSHandle<JSTaggedValue> valueX, const JSHandle<JSTaggedValue> valueY)343     inline static ComparisonResult OrdinayEntryCompare(JSThread *thread, const JSHandle<JSTaggedValue> valueX,
344                                                        const JSHandle<JSTaggedValue> valueY)
345     {
346         if (valueX->IsString() && valueY->IsString()) {
347             auto xHandle = JSHandle<EcmaString>(valueX);
348             auto yHandle = JSHandle<EcmaString>(valueY);
349             int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
350             if (result < 0) {
351                 return ComparisonResult::LESS;
352             }
353             if (result == 0) {
354                 return ComparisonResult::EQUAL;
355             }
356             return ComparisonResult::GREAT;
357         }
358 
359         if (valueX->IsNumber() && valueY->IsNumber()) {
360             return JSTaggedValue::StrictNumberCompare(valueX->GetNumber(), valueY->GetNumber());
361         }
362 
363         if (valueX->IsNumber() && valueY->IsString()) {
364             return ComparisonResult::LESS;
365         }
366         if (valueX->IsString() && valueY->IsNumber()) {
367             return ComparisonResult::GREAT;
368         }
369 
370         JSHandle<JSTaggedValue> xValueHandle(JSTaggedValue::ToString(thread, valueX));
371         JSHandle<JSTaggedValue> yValueHandle(JSTaggedValue::ToString(thread, valueY));
372         ASSERT_NO_ABRUPT_COMPLETION(thread);
373         return JSTaggedValue::Compare(thread, xValueHandle, yValueHandle);
374     }
375 
CopyEntry(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)376     inline void CopyEntry(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)
377     {
378         newTree->SetKey(thread, index, GetKey(parent));
379         newTree->SetColor(thread, index, GetColor(parent));
380     }
381 
CopyData(const JSThread *thread, int dst, int src)382     inline void CopyData(const JSThread *thread, int dst, int src)
383     {
384         SetKey(thread, dst, GetKey(src));
385     }
CopyAllData(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)386     inline void CopyAllData(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)
387     {
388         newTree->SetKey(thread, index, GetKey(parent));
389         newTree->SetValue(thread, index, GetValue(parent));
390         newTree->SetColor(thread, index, GetColor(parent));
391         newTree->SetParent(thread, index, JSTaggedValue(GetParent(parent)));
392         newTree->SetRightChild(thread, index, GetRightChild(parent));
393         newTree->SetLeftChild(thread, index, GetLeftChild(parent));
394     }
395 
RemoveEntry(const JSThread *thread, int index)396     inline void RemoveEntry(const JSThread *thread, int index)
397     {
398         SetKey(thread, index, JSTaggedValue::Hole());
399         SetParent(thread, index, JSTaggedValue::Hole());
400         SetLeftChild(thread, index, JSTaggedValue::Hole());
401         SetRightChild(thread, index, JSTaggedValue::Hole());
402     }
403 
Transform(JSTaggedValue v) const404     inline JSTaggedValue Transform(JSTaggedValue v) const
405     {
406         return v.IsHole() ? JSTaggedValue::Undefined() : v;
407     }
408 
409     void Transplant(const JSThread *thread, int dst, int src);
410 
411     static JSTaggedValue GetLowerKey(JSThread *thread, const JSHandle<Derived> &tree,
412                                      const JSHandle<JSTaggedValue> &key);
413     static JSTaggedValue GetHigherKey(JSThread *thread, const JSHandle<Derived> &tree,
414                                       const JSHandle<JSTaggedValue> &key);
415     static JSHandle<TaggedArray> GetSortArray(const JSThread *thread, const JSHandle<Derived> &tree);
416     static JSHandle<Derived> Shrink(const JSThread *thread, const JSHandle<Derived> &tree);
417 };
418 
419 
420 class TaggedTreeMap : public TaggedTree<TaggedTreeMap> {
421 public:
422     using RBTree = TaggedTree<TaggedTreeMap>;
Cast(TaggedObject *obj)423     static TaggedTreeMap *Cast(TaggedObject *obj)
424     {
425         return static_cast<TaggedTreeMap *>(obj);
426     }
427 
428     static JSTaggedValue Create(const JSThread *thread, int numberOfElements = MIN_CAPACITY);
429     static JSTaggedValue Set(JSThread *thread, JSHandle<TaggedTreeMap> &obj,
430                                     const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
Get(JSThread *thread, const JSHandle<TaggedTreeMap> &map, const JSHandle<JSTaggedValue> &key)431     inline static JSTaggedValue Get(JSThread *thread, const JSHandle<TaggedTreeMap> &map,
432                                     const JSHandle<JSTaggedValue> &key)
433     {
434         int index = RBTree::FindEntry(thread, map, key);
435         return index == -1 ? JSTaggedValue::Undefined() : map->GetValue(index);
436     }
437 
438     static JSTaggedValue Delete(JSThread *thread, const JSHandle<TaggedTreeMap> &map, int entry);
439     bool HasValue(const JSThread *thread, JSTaggedValue value) const;
440 
441     static JSTaggedValue GetLowerKey(JSThread *thread, const JSHandle<TaggedTreeMap> &map,
442                                      const JSHandle<JSTaggedValue> &key);
443     static JSTaggedValue GetHigherKey(JSThread *thread, const JSHandle<TaggedTreeMap> &map,
444                                       const JSHandle<JSTaggedValue> &key);
445 
GetFirstKey() const446     inline JSTaggedValue GetFirstKey() const
447     {
448         JSTaggedValue key = GetKey(GetMinimum(GetRootEntries()));
449         return Transform(key);
450     }
451 
GetLastKey() const452     inline JSTaggedValue GetLastKey() const
453     {
454         JSTaggedValue key = GetKey(GetMaximum(GetRootEntries()));
455         return Transform(key);
456     }
457 
458     static JSTaggedValue SetAll(JSThread *thread, JSHandle<TaggedTreeMap> &dst, const JSHandle<TaggedTreeMap> &src);
459     static JSHandle<TaggedArray> GetArrayFromMap(const JSThread *thread, const JSHandle<TaggedTreeMap> &map);
460     static int FindEntry(JSThread *thread, const JSHandle<TaggedTreeMap> &map, const JSHandle<JSTaggedValue> &key);
461 
462     static const int ENTRY_SIZE = 6;
463     static const int ENTRY_VALUE_INDEX = 1;
464     static const int ENTRY_COLOR_INDEX = 2;
465     static const int ENTRY_PARENT_INDEX = 3;
466     static const int ENTRY_LEFT_CHILD_INDEX = 4;
467     static const int ENTRY_RIGHT_CHILD_INDEX = 5;
468     DECL_DUMP()
469 
CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeMap> &newMap, int index)470     inline void CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeMap> &newMap, int index)
471     {
472         RBTree::CopyEntry(thread, parent, newMap, index);
473         newMap->SetValue(thread, index, GetValue(parent));
474     }
CopyData(const JSThread *thread, int dst, int src)475     inline void CopyData(const JSThread *thread, int dst, int src)
476     {
477         RBTree::CopyData(thread, dst, src);
478         SetValue(thread, dst, GetValue(src));
479     }
480 
RemoveEntry(const JSThread *thread, int index)481     inline void RemoveEntry(const JSThread *thread, int index)
482     {
483         RBTree::RemoveEntry(thread, index);
484         SetValue(thread, index, JSTaggedValue::Hole());
485     }
486 };
487 
488 class TaggedTreeSet : public TaggedTree<TaggedTreeSet> {
489 public:
490     using RBTree = TaggedTree<TaggedTreeSet>;
Cast(TaggedObject *obj)491     static TaggedTreeSet *Cast(TaggedObject *obj)
492     {
493         return static_cast<TaggedTreeSet *>(obj);
494     }
495 
496     static JSTaggedValue Create(const JSThread *thread, int numberOfElements = MIN_CAPACITY);
497     static JSTaggedValue Add(JSThread *thread, JSHandle<TaggedTreeSet> &obj, const JSHandle<JSTaggedValue> &value);
498     static JSTaggedValue Delete(JSThread *thread, const JSHandle<TaggedTreeSet> &set, int entry);
499 
500     static JSTaggedValue GetLowerKey(JSThread *thread, const JSHandle<TaggedTreeSet> &set,
501                                      const JSHandle<JSTaggedValue> &key);
502     static JSTaggedValue GetHigherKey(JSThread *thread, const JSHandle<TaggedTreeSet> &set,
503                                       const JSHandle<JSTaggedValue> &key);
504 
GetFirstKey() const505     inline JSTaggedValue GetFirstKey() const
506     {
507         JSTaggedValue key = GetKey(GetMinimum(GetRootEntries()));
508         return Transform(key);
509     }
510 
GetLastKey() const511     inline JSTaggedValue GetLastKey() const
512     {
513         JSTaggedValue key = GetKey(GetMaximum(GetRootEntries()));
514         return Transform(key);
515     }
516 
517     static JSHandle<TaggedArray> GetArrayFromSet(const JSThread *thread, const JSHandle<TaggedTreeSet> &set);
518     static int FindEntry(JSThread *thread, const JSHandle<TaggedTreeSet> &set, const JSHandle<JSTaggedValue> &key);
519 
520     static const int ENTRY_SIZE = 5;
521     static const int ENTRY_VALUE_INDEX = 0;
522     static const int ENTRY_COLOR_INDEX = 1;
523     static const int ENTRY_PARENT_INDEX = 2;
524     static const int ENTRY_LEFT_CHILD_INDEX = 3;
525     static const int ENTRY_RIGHT_CHILD_INDEX = 4;
526 
527     DECL_DUMP()
528 
CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeSet> &newMap, int index)529     inline void CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeSet> &newMap, int index)
530     {
531         RBTree::CopyEntry(thread, parent, newMap, index);
532         newMap->SetValue(thread, index, GetValue(parent));
533     }
534 
CopyData(const JSThread *thread, int dst, int src)535     inline void CopyData(const JSThread *thread, int dst, int src)
536     {
537         RBTree::CopyData(thread, dst, src);
538         SetValue(thread, dst, GetValue(src));
539     }
540 
RemoveEntry(const JSThread *thread, int index)541     inline void RemoveEntry(const JSThread *thread, int index)
542     {
543         RBTree::RemoveEntry(thread, index);
544         SetValue(thread, index, JSTaggedValue::Hole());
545     }
546 };
547 }  // namespace panda::ecmascript
548 #endif  // ECMASCRIPT_TAGGED_TREE_H
549