1 /*
2 * Copyright (c) 2021 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_INL_H
17 #define ECMASCRIPT_TAGGED_TREE_INL_H
18
19 #include "ecmascript/tagged_tree.h"
20
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/internal_call_params.h"
23 #include "tagged_array-inl.h"
24 #include "utils/bit_utils.h"
25
26 namespace panda::ecmascript {
27 // TaggedTree
28 template<typename Derived>
GetRootKey()29 JSTaggedValue TaggedTree<Derived>::GetRootKey() const
30 {
31 return GetKey(GetRootEntries());
32 }
33
34 template<typename Derived>
SetRoot(JSThread * thread,int index,JSTaggedValue key,JSTaggedValue value)35 void TaggedTree<Derived>::SetRoot(JSThread *thread, int index, JSTaggedValue key, JSTaggedValue value)
36 {
37 SetKey(thread, 0, key);
38 SetValue(thread, 0, value);
39 SetParent(thread, 0, JSTaggedValue(-1));
40 SetColor(thread, 0, TreeColor::BLACK);
41 SetRootEntries(thread, index);
42 }
43
44 template<typename Derived>
SetKey(const JSThread * thread,uint32_t entry,JSTaggedValue key)45 void TaggedTree<Derived>::SetKey(const JSThread *thread, uint32_t entry, JSTaggedValue key)
46 {
47 uint32_t index = EntryToIndex(entry);
48 SetElement(thread, index, key);
49 }
50
51 template<typename Derived>
SetValue(const JSThread * thread,uint32_t entry,JSTaggedValue value)52 void TaggedTree<Derived>::SetValue(const JSThread *thread, uint32_t entry, JSTaggedValue value)
53 {
54 uint32_t index = EntryToIndex(entry) + Derived::ENTRY_VALUE_INDEX;
55 SetElement(thread, index, value);
56 }
57
58 template<typename Derived>
SetColor(const JSThread * thread,int entry,TreeColor color)59 void TaggedTree<Derived>::SetColor(const JSThread *thread, int entry, TreeColor color)
60 {
61 if (entry >= 0) {
62 uint32_t index = EntryToIndex(entry) + Derived::ENTRY_COLOR_INDEX;
63 SetElement(thread, index, JSTaggedValue(static_cast<int>(color)));
64 }
65 }
66
67 template<typename Derived>
SetParent(const JSThread * thread,int entry,JSTaggedValue value)68 void TaggedTree<Derived>::SetParent(const JSThread *thread, int entry, JSTaggedValue value)
69 {
70 if (entry < 0) {
71 return;
72 }
73 uint32_t index = EntryToIndex(entry) + Derived::ENTRY_PARENT_INDEX;
74 SetElement(thread, index, value);
75 }
76
77 template<typename Derived>
SetLeftChild(const JSThread * thread,uint32_t entry,JSTaggedValue value)78 void TaggedTree<Derived>::SetLeftChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)
79 {
80 uint32_t index = EntryToIndex(entry) + Derived::ENTRY_LEFT_CHILD_INDEX;
81 SetElement(thread, index, value);
82 }
83
84 template<typename Derived>
SetRightChild(const JSThread * thread,uint32_t entry,JSTaggedValue value)85 void TaggedTree<Derived>::SetRightChild(const JSThread *thread, uint32_t entry, JSTaggedValue value)
86 {
87 uint32_t index = EntryToIndex(entry) + Derived::ENTRY_RIGHT_CHILD_INDEX;
88 SetElement(thread, index, value);
89 }
90
91 template<typename Derived>
SetCompare(const JSThread * thread,JSTaggedValue fn)92 void TaggedTree<Derived>::SetCompare(const JSThread *thread, JSTaggedValue fn)
93 {
94 Set(thread, COMPARE_FUNCTION_INDEX, fn);
95 }
96
97 template<typename Derived>
GetCompare()98 JSTaggedValue TaggedTree<Derived>::GetCompare() const
99 {
100 return Get(COMPARE_FUNCTION_INDEX);
101 }
102
103 template<typename Derived>
GetKey(int entry)104 JSTaggedValue TaggedTree<Derived>::GetKey(int entry) const
105 {
106 if (entry < 0) {
107 return JSTaggedValue::Hole();
108 }
109 int index = EntryToIndex(entry);
110 return GetElement(index);
111 }
112
113 template<typename Derived>
GetValue(int entry)114 JSTaggedValue TaggedTree<Derived>::GetValue(int entry) const
115 {
116 int index = EntryToIndex(entry) + Derived::ENTRY_VALUE_INDEX;
117 return GetElement(index);
118 }
119
120 template<typename Derived>
GetColor(int entry)121 TreeColor TaggedTree<Derived>::GetColor(int entry) const
122 {
123 if (entry < 0) {
124 return TreeColor::BLACK;
125 }
126 int index = EntryToIndex(entry) + Derived::ENTRY_COLOR_INDEX;
127 JSTaggedValue color = GetElement(index);
128 return color.GetInt() == TreeColor::RED ? TreeColor::RED : TreeColor::BLACK;
129 }
130
131 template<typename Derived>
EntryToIndex(uint32_t entry)132 uint32_t TaggedTree<Derived>::EntryToIndex(uint32_t entry) const
133 {
134 return ELEMENTS_START_INDEX + entry * (Derived::ENTRY_SIZE);
135 }
136
137 template<typename Derived>
SetElement(const JSThread * thread,uint32_t index,JSTaggedValue element)138 void TaggedTree<Derived>::SetElement(const JSThread *thread, uint32_t index, JSTaggedValue element)
139 {
140 ASSERT(index >= 0 && index < GetLength());
141 Set(thread, index, element);
142 }
143
144 template<typename Derived>
GetElement(int index)145 JSTaggedValue TaggedTree<Derived>::GetElement(int index) const
146 {
147 ASSERT(index >= 0 && index < static_cast<int>(GetLength()));
148 return Get(index);
149 }
150
151 template<typename Derived>
NumberOfElements()152 int TaggedTree<Derived>::NumberOfElements() const
153 {
154 return Get(NUMBER_OF_ELEMENTS_INDEX).GetInt();
155 }
156
157 template<typename Derived>
NumberOfDeletedElements()158 int TaggedTree<Derived>::NumberOfDeletedElements() const
159 {
160 return Get(NUMBER_OF_HOLE_ENTRIES_INDEX).GetInt();
161 }
162
163 template<typename Derived>
SetNumberOfElements(const JSThread * thread,int num)164 void TaggedTree<Derived>::SetNumberOfElements(const JSThread *thread, int num)
165 {
166 Set(thread, NUMBER_OF_ELEMENTS_INDEX, JSTaggedValue(num));
167 }
168
169 template<typename Derived>
SetNumberOfDeletedElements(const JSThread * thread,int num)170 void TaggedTree<Derived>::SetNumberOfDeletedElements(const JSThread *thread, int num)
171 {
172 Set(thread, NUMBER_OF_HOLE_ENTRIES_INDEX, JSTaggedValue(num));
173 }
174
175 template<typename Derived>
SetRootEntries(const JSThread * thread,int num)176 void TaggedTree<Derived>::SetRootEntries(const JSThread *thread, int num)
177 {
178 Set(thread, ROOT_INDEX, JSTaggedValue(num));
179 }
180
181 template<typename Derived>
GetRootEntries()182 int TaggedTree<Derived>::GetRootEntries() const
183 {
184 return Get(ROOT_INDEX).GetInt();
185 }
186
187 template<typename Derived>
GetLeftChild(int parent)188 JSTaggedValue TaggedTree<Derived>::GetLeftChild(int parent) const
189 {
190 if (parent < 0) {
191 return JSTaggedValue::Hole();
192 }
193 int index = EntryToIndex(parent) + Derived::ENTRY_LEFT_CHILD_INDEX;
194 return Get(index);
195 }
196
197 template<typename Derived>
GetRightChild(int parent)198 JSTaggedValue TaggedTree<Derived>::GetRightChild(int parent) const
199 {
200 if (parent < 0) {
201 return JSTaggedValue::Hole();
202 }
203 int index = EntryToIndex(parent) + Derived::ENTRY_RIGHT_CHILD_INDEX;
204 return Get(index);
205 }
206
207 template<typename Derived>
GetLeftChildIndex(int parent)208 int TaggedTree<Derived>::GetLeftChildIndex(int parent) const
209 {
210 if (parent < 0) {
211 return -1;
212 }
213 int index = EntryToIndex(parent) + Derived::ENTRY_LEFT_CHILD_INDEX;
214 JSTaggedValue child = Get(index);
215 return child.IsHole() ? -1 : child.GetInt();
216 }
217
218 template<typename Derived>
GetRightChildIndex(int parent)219 int TaggedTree<Derived>::GetRightChildIndex(int parent) const
220 {
221 if (parent < 0) {
222 return -1;
223 }
224 int index = EntryToIndex(parent) + Derived::ENTRY_RIGHT_CHILD_INDEX;
225 JSTaggedValue child = Get(index);
226 return child.IsHole() ? -1: child.GetInt();
227 }
228
229 template<typename Derived>
GetParent(int entry)230 int TaggedTree<Derived>::GetParent(int entry) const
231 {
232 int index = EntryToIndex(entry) + Derived::ENTRY_PARENT_INDEX;
233 JSTaggedValue parent = GetElement(index);
234 return parent.GetInt();
235 }
236
237 template<typename Derived>
GetMinimum(int entry)238 int TaggedTree<Derived>::GetMinimum(int entry) const
239 {
240 JSTaggedValue child = GetLeftChild(entry);
241 while (!child.IsHole()) {
242 entry = child.GetInt();
243 child = GetLeftChild(entry);
244 }
245 return entry;
246 }
247
248 template<typename Derived>
GetMaximum(int entry)249 int TaggedTree<Derived>::GetMaximum(int entry) const
250 {
251 JSTaggedValue child = GetRightChild(entry);
252 while (!child.IsHole()) {
253 entry = child.GetInt();
254 child = GetRightChild(entry);
255 }
256 return entry;
257 }
258
259 template<typename Derived>
IsLeft(int entry)260 bool TaggedTree<Derived>::IsLeft(int entry) const
261 {
262 JSTaggedValue child = GetLeftChild(GetParent(entry));
263 return child.IsHole() ? false : (child.GetInt() == entry);
264 }
265
266 template<typename Derived>
IsRight(int entry)267 bool TaggedTree<Derived>::IsRight(int entry) const
268 {
269 JSTaggedValue child = GetRightChild(GetParent(entry));
270 return child.IsHole() ? false : (child.GetInt() == entry);
271 }
272
273 template<typename Derived>
IsVaildIndex(int entry)274 bool TaggedTree<Derived>::IsVaildIndex(int entry) const
275 {
276 return entry != GetRootEntries() && !GetKey(entry).IsHole();
277 }
278
279 template<typename Derived>
GetLeftBrother(int entry)280 int TaggedTree<Derived>::GetLeftBrother(int entry) const
281 {
282 JSTaggedValue child = GetRightChild(GetParent(entry));
283 return child.IsHole() ? -1 : child.GetInt();
284 }
285
286 template<typename Derived>
GetRightBrother(int entry)287 int TaggedTree<Derived>::GetRightBrother(int entry) const
288 {
289 JSTaggedValue child = GetLeftChild(GetParent(entry));
290 return child.IsHole() ? -1 : child.GetInt();
291 }
292
293 template<typename Derived>
SetCapacity(const JSThread * thread,int capacity)294 void TaggedTree<Derived>::SetCapacity(const JSThread *thread, int capacity)
295 {
296 Set(thread, CAPACITY_INDEX, JSTaggedValue(capacity));
297 }
298
299 template<typename Derived>
Capacity()300 int TaggedTree<Derived>::Capacity() const
301 {
302 return Get(CAPACITY_INDEX).GetInt();
303 }
304
305 template<typename Derived>
ComputeCapacity(int oldCapacity)306 int TaggedTree<Derived>::ComputeCapacity(int oldCapacity)
307 {
308 int capacity = (oldCapacity << 1) + 1;
309 return (capacity > MIN_CAPACITY) ? capacity : MIN_CAPACITY;
310 }
311
312 template<typename Derived>
InsertLeftEntry(const JSThread * thread,uint32_t parentIndex,uint32_t entry,JSTaggedValue key,JSTaggedValue value)313 void TaggedTree<Derived>::InsertLeftEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry,
314 JSTaggedValue key, JSTaggedValue value)
315 {
316 SetKey(thread, entry, key);
317 SetValue(thread, entry, value);
318 SetColor(thread, entry, TreeColor::RED);
319 SetParent(thread, entry, JSTaggedValue(parentIndex));
320 SetLeftChild(thread, parentIndex, JSTaggedValue(entry));
321 }
322
323 template<typename Derived>
InsertRightEntry(const JSThread * thread,uint32_t parentIndex,uint32_t entry,JSTaggedValue key,JSTaggedValue value)324 void TaggedTree<Derived>::InsertRightEntry(const JSThread *thread, uint32_t parentIndex, uint32_t entry,
325 JSTaggedValue key, JSTaggedValue value)
326 {
327 SetKey(thread, entry, key);
328 SetValue(thread, entry, value);
329 SetColor(thread, entry, TreeColor::RED);
330 SetParent(thread, entry, JSTaggedValue(parentIndex));
331 SetRightChild(thread, parentIndex, JSTaggedValue(entry));
332 }
333
334 template<typename Derived>
CopyEntry(const JSThread * thread,int parent,const JSHandle<Derived> & newTree,int index)335 void TaggedTree<Derived>::CopyEntry(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)
336 {
337 newTree->SetKey(thread, index, GetKey(parent));
338 newTree->SetColor(thread, index, GetColor(parent));
339 }
340
341 template<typename Derived>
CopyData(const JSThread * thread,int dst,int src)342 void TaggedTree<Derived>::CopyData(const JSThread *thread, int dst, int src)
343 {
344 SetKey(thread, dst, GetKey(src));
345 }
346
347 template<typename Derived>
CopyAllData(const JSThread * thread,int parent,const JSHandle<Derived> & newTree,int index)348 void TaggedTree<Derived>::CopyAllData(const JSThread *thread, int parent, const JSHandle<Derived> &newTree, int index)
349 {
350 newTree->SetKey(thread, index, GetKey(parent));
351 newTree->SetValue(thread, index, GetValue(parent));
352 newTree->SetColor(thread, index, GetColor(parent));
353 newTree->SetParent(thread, index, JSTaggedValue(GetParent(parent)));
354 newTree->SetRightChild(thread, index, GetRightChild(parent));
355 newTree->SetLeftChild(thread, index, GetLeftChild(parent));
356 }
357
358 template<typename Derived>
RemoveEntry(const JSThread * thread,int index)359 void TaggedTree<Derived>::RemoveEntry(const JSThread *thread, int index)
360 {
361 SetKey(thread, index, JSTaggedValue::Hole());
362 SetParent(thread, index, JSTaggedValue::Hole());
363 SetLeftChild(thread, index, JSTaggedValue::Hole());
364 SetRightChild(thread, index, JSTaggedValue::Hole());
365 }
366
367 template<typename Derived>
EntryCompare(JSThread * thread,const JSHandle<JSTaggedValue> valueX,const JSHandle<JSTaggedValue> valueY,JSHandle<Derived> tree)368 ComparisonResult TaggedTree<Derived>::EntryCompare(JSThread *thread, const JSHandle<JSTaggedValue> valueX,
369 const JSHandle<JSTaggedValue> valueY, JSHandle<Derived> tree)
370 {
371 JSTaggedValue fn = tree->GetCompare();
372 if (fn.IsHole()) {
373 return OrdinayEntryCompare(thread, valueX, valueY);
374 }
375
376 JSHandle<JSTaggedValue> compareFn(thread, fn);
377 JSHandle<JSTaggedValue> thisArgHandle = thread->GlobalConstants()->GetHandledUndefined();
378 InternalCallParams *arguments = thread->GetInternalCallParams();
379 arguments->MakeArgv(valueX, valueY);
380 JSTaggedValue callResult =
381 JSFunction::Call(thread, compareFn, thisArgHandle, 2, arguments->GetArgv()); // 2: two args
382 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
383 int compareResult = 0;
384 if (callResult.IsInt()) {
385 compareResult = callResult.GetInt();
386 } else {
387 JSHandle<JSTaggedValue> resultHandle(thread, callResult);
388 JSTaggedNumber v = JSTaggedValue::ToNumber(thread, resultHandle);
389 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
390 double value = v.GetNumber();
391 if (std::isnan(value)) {
392 THROW_TYPE_ERROR_AND_RETURN(thread, "CompareFn has illegal return value", ComparisonResult::UNDEFINED);
393 }
394 compareResult = static_cast<int>(value);
395 }
396 return compareResult > 0 ? ComparisonResult::GREAT :
397 (compareResult < 0 ? ComparisonResult::LESS : ComparisonResult::EQUAL);
398 }
399
400 template<typename Derived>
OrdinayEntryCompare(JSThread * thread,const JSHandle<JSTaggedValue> valueX,const JSHandle<JSTaggedValue> valueY)401 ComparisonResult TaggedTree<Derived>::OrdinayEntryCompare(JSThread *thread, const JSHandle<JSTaggedValue> valueX,
402 const JSHandle<JSTaggedValue> valueY)
403 {
404 if (valueX->IsString() && valueY->IsString()) {
405 auto xString = static_cast<EcmaString *>(valueX->GetTaggedObject());
406 auto yString = static_cast<EcmaString *>(valueY->GetTaggedObject());
407 int result = xString->Compare(yString);
408 if (result < 0) {
409 return ComparisonResult::LESS;
410 }
411 if (result == 0) {
412 return ComparisonResult::EQUAL;
413 }
414 return ComparisonResult::GREAT;
415 }
416
417 if (valueX->IsNumber() && valueY->IsNumber()) {
418 return JSTaggedValue::StrictNumberCompare(valueX->GetNumber(), valueY->GetNumber());
419 }
420
421 if (valueX->IsNumber() && valueY->IsString()) {
422 return ComparisonResult::LESS;
423 }
424 if (valueX->IsString() && valueY->IsNumber()) {
425 return ComparisonResult::GREAT;
426 }
427
428 JSHandle<JSTaggedValue> xValueHandle(JSTaggedValue::ToString(thread, valueX));
429 JSHandle<JSTaggedValue> yValueHandle(JSTaggedValue::ToString(thread, valueY));
430 ASSERT_NO_ABRUPT_COMPLETION(thread);
431 return JSTaggedValue::Compare(thread, xValueHandle, yValueHandle);
432 }
433
434 template<typename Derived>
Transform(JSTaggedValue v)435 JSTaggedValue TaggedTree<Derived>::Transform(JSTaggedValue v) const
436 {
437 return v.IsHole() ? JSTaggedValue::Undefined() : v;
438 }
439
440 // TaggedTreeMap
CopyEntry(const JSThread * thread,int parent,const JSHandle<TaggedTreeMap> & newMap,int index)441 void TaggedTreeMap::CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeMap> &newMap, int index)
442 {
443 RBTree::CopyEntry(thread, parent, newMap, index);
444 newMap->SetValue(thread, index, GetValue(parent));
445 }
446
CopyData(const JSThread * thread,int dst,int src)447 void TaggedTreeMap::CopyData(const JSThread *thread, int dst, int src)
448 {
449 RBTree::CopyData(thread, dst, src);
450 SetValue(thread, dst, GetValue(src));
451 }
452
RemoveEntry(const JSThread * thread,int index)453 void TaggedTreeMap::RemoveEntry(const JSThread *thread, int index)
454 {
455 RBTree::RemoveEntry(thread, index);
456 SetValue(thread, index, JSTaggedValue::Hole());
457 }
458
Get(JSThread * thread,const JSHandle<TaggedTreeMap> & map,const JSHandle<JSTaggedValue> & key)459 JSTaggedValue TaggedTreeMap::Get(JSThread *thread, const JSHandle<TaggedTreeMap> &map,
460 const JSHandle<JSTaggedValue> &key)
461 {
462 int index = RBTree::FindEntry(thread, map, key);
463 return index == -1 ? JSTaggedValue::Undefined() : map->GetValue(index);
464 }
465
GetFirstKey()466 JSTaggedValue TaggedTreeMap::GetFirstKey() const
467 {
468 JSTaggedValue key = GetKey(GetMinimum(GetRootEntries()));
469 return Transform(key);
470 }
471
GetLastKey()472 JSTaggedValue TaggedTreeMap::GetLastKey() const
473 {
474 JSTaggedValue key = GetKey(GetMaximum(GetRootEntries()));
475 return Transform(key);
476 }
477
478 // TaggedTreeSet
CopyEntry(const JSThread * thread,int parent,const JSHandle<TaggedTreeSet> & newMap,int index)479 void TaggedTreeSet::CopyEntry(const JSThread *thread, int parent, const JSHandle<TaggedTreeSet> &newMap, int index)
480 {
481 RBTree::CopyEntry(thread, parent, newMap, index);
482 newMap->SetValue(thread, index, GetValue(parent));
483 }
484
CopyData(const JSThread * thread,int dst,int src)485 void TaggedTreeSet::CopyData(const JSThread *thread, int dst, int src)
486 {
487 RBTree::CopyData(thread, dst, src);
488 SetValue(thread, dst, GetValue(src));
489 }
490
RemoveEntry(const JSThread * thread,int index)491 void TaggedTreeSet::RemoveEntry(const JSThread *thread, int index)
492 {
493 RBTree::RemoveEntry(thread, index);
494 SetValue(thread, index, JSTaggedValue::Hole());
495 }
496
GetFirstKey()497 JSTaggedValue TaggedTreeSet::GetFirstKey() const
498 {
499 JSTaggedValue key = GetKey(GetMinimum(GetRootEntries()));
500 return Transform(key);
501 }
502
GetLastKey()503 JSTaggedValue TaggedTreeSet::GetLastKey() const
504 {
505 JSTaggedValue key = GetKey(GetMaximum(GetRootEntries()));
506 return Transform(key);
507 }
508 } // namespace panda::ecmascript
509 #endif // ECMASCRIPT_TAGGED_TREE_INL_H
510