• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/containers/containers_treemap.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_api/js_api_tree_map.h"
22 #include "ecmascript/js_api/js_api_tree_map_iterator.h"
23 #include "ecmascript/object_factory.h"
24 #include "ecmascript/tagged_array-inl.h"
25 #include "ecmascript/tagged_tree.h"
26 
27 namespace panda::ecmascript::containers {
TreeMapConstructor(EcmaRuntimeCallInfo * argv)28 JSTaggedValue ContainersTreeMap::TreeMapConstructor(EcmaRuntimeCallInfo *argv)
29 {
30     ASSERT(argv);
31     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Constructor);
32     JSThread *thread = argv->GetThread();
33     [[maybe_unused]] EcmaHandleScope handleScope(thread);
34     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
35 
36     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
37     if (newTarget->IsUndefined()) {
38         JSTaggedValue error =
39             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
40                                           "The TreeMap's constructor cannot be directly invoked");
41         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
42     }
43 
44     // new TreeMap
45     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
46     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
47     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48 
49     // Set map’s internal slot with a new empty List.
50     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(obj);
51     JSTaggedValue internal = TaggedTreeMap::Create(thread);
52     map->SetTreeMap(thread, internal);
53 
54     // If comparefn was supplied, let compare be comparefn; else let compare be hole.
55     JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
56     if (compareFn->IsUndefined() || compareFn->IsNull()) {
57         return map.GetTaggedValue();
58     }
59     if (!compareFn->IsCallable()) {
60         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue());
61         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
62         CString errorMsg =
63             "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
64         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
65         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
66     }
67 
68     TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
69     return map.GetTaggedValue();
70 }
71 
Set(EcmaRuntimeCallInfo * argv)72 JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv)
73 {
74     ASSERT(argv);
75     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set);
76     JSThread *thread = argv->GetThread();
77     [[maybe_unused]] EcmaHandleScope handleScope(thread);
78     JSHandle<JSTaggedValue> self = GetThis(argv);
79     // get and check this map
80     if (!self->IsJSAPITreeMap()) {
81         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
82             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
83         } else {
84             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
85                                                                 "The set method cannot be bound");
86             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
87         }
88     }
89 
90     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
91     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
92 
93     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
94     JSAPITreeMap::Set(thread, map, key, value);
95     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
96     return map.GetTaggedValue();
97 }
98 
Get(EcmaRuntimeCallInfo * argv)99 JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv)
100 {
101     ASSERT(argv);
102     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get);
103     JSThread *thread = argv->GetThread();
104     [[maybe_unused]] EcmaHandleScope handleScope(thread);
105     // get and check this map
106     JSHandle<JSTaggedValue> self(GetThis(argv));
107     if (!self->IsJSAPITreeMap()) {
108         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
109             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
110         } else {
111             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
112                                                                 "The get method cannot be bound");
113             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
114         }
115     }
116 
117     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
118     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
119     return JSAPITreeMap::Get(thread, map, key);
120 }
121 
Remove(EcmaRuntimeCallInfo * argv)122 JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv)
123 {
124     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove);
125     JSThread *thread = argv->GetThread();
126     [[maybe_unused]] EcmaHandleScope handleScope(thread);
127     JSHandle<JSTaggedValue> self = GetThis(argv);
128     // get and check this map
129     if (!self->IsJSAPITreeMap()) {
130         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
131             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
132         } else {
133             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
134                                                                 "The remove method cannot be bound");
135             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
136         }
137     }
138 
139     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
140     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
141     return JSAPITreeMap::Delete(thread, map, key);
142 }
143 
HasKey(EcmaRuntimeCallInfo * argv)144 JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv)
145 {
146     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey);
147     JSThread *thread = argv->GetThread();
148     [[maybe_unused]] EcmaHandleScope handleScope(thread);
149     // get and check this map
150     JSHandle<JSTaggedValue> self(GetThis(argv));
151     if (!self->IsJSAPITreeMap()) {
152         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
153             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
154         } else {
155             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
156                                                                 "The hasKey method cannot be bound");
157             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
158         }
159     }
160 
161     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
162     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
163 
164     bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key);
165     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
166     return GetTaggedBoolean(flag);
167 }
168 
HasValue(EcmaRuntimeCallInfo * argv)169 JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv)
170 {
171     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue);
172     JSThread *thread = argv->GetThread();
173     [[maybe_unused]] EcmaHandleScope handleScope(thread);
174     // get and check this map
175     JSHandle<JSTaggedValue> self(GetThis(argv));
176     if (!self->IsJSAPITreeMap()) {
177         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
178             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
179         } else {
180             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
181                                                                 "The hasValue method cannot be bound");
182             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
183         }
184     }
185 
186     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
187     bool flag = map->HasValue(thread, GetCallArg(argv, 0));
188     return GetTaggedBoolean(flag);
189 }
190 
GetFirstKey(EcmaRuntimeCallInfo * argv)191 JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv)
192 {
193     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey);
194     JSThread *thread = argv->GetThread();
195     [[maybe_unused]] EcmaHandleScope handleScope(thread);
196     // get and check this map
197     JSHandle<JSTaggedValue> self(GetThis(argv));
198     if (!self->IsJSAPITreeMap()) {
199         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
200             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
201         } else {
202             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
203                                                                 "The getFirstKey method cannot be bound");
204             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
205         }
206     }
207 
208     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
209     return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey();
210 }
211 
GetLastKey(EcmaRuntimeCallInfo * argv)212 JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv)
213 {
214     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey);
215     JSThread *thread = argv->GetThread();
216     [[maybe_unused]] EcmaHandleScope handleScope(thread);
217     // get and check this map
218     JSHandle<JSTaggedValue> self(GetThis(argv));
219     if (!self->IsJSAPITreeMap()) {
220         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
221             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
222         } else {
223             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
224                                                                 "The getLastKey method cannot be bound");
225             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
226         }
227     }
228 
229     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
230     return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey();
231 }
232 
SetAll(EcmaRuntimeCallInfo * argv)233 JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv)
234 {
235     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll);
236     JSThread *thread = argv->GetThread();
237     [[maybe_unused]] EcmaHandleScope handleScope(thread);
238     // get and check this map
239     JSHandle<JSTaggedValue> self(GetThis(argv));
240     if (!self->IsJSAPITreeMap()) {
241         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
242             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
243         } else {
244             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
245                                                                 "The setAll method cannot be bound");
246             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
247         }
248     }
249 
250     JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
251     if (!obj->IsJSAPITreeMap()) {
252         if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) {
253             obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
254         } else {
255             JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue());
256             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
257             CString errorMsg =
258                 "The type of \"map\" must be TreeMap. Received value is: " + ConvertToString(*result);
259             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
260             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
261         }
262     }
263 
264     JSHandle<JSAPITreeMap> dst = JSHandle<JSAPITreeMap>::Cast(self);
265     JSHandle<TaggedTreeMap> dmap(thread, dst->GetTreeMap());
266     JSHandle<TaggedTreeMap> smap(thread, JSHandle<JSAPITreeMap>::Cast(obj)->GetTreeMap());
267 
268     JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
269     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
270     dst->SetTreeMap(thread, tmap);
271     return JSTaggedValue::Undefined();
272 }
273 
Clear(EcmaRuntimeCallInfo * argv)274 JSTaggedValue ContainersTreeMap::Clear(EcmaRuntimeCallInfo *argv)
275 {
276     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Clear);
277     JSThread *thread = argv->GetThread();
278     [[maybe_unused]] EcmaHandleScope handleScope(thread);
279     // get and check this map
280     JSHandle<JSTaggedValue> self(GetThis(argv));
281     if (!self->IsJSAPITreeMap()) {
282         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
283             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
284         } else {
285             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
286                                                                 "The clear method cannot be bound");
287             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
288         }
289     }
290 
291     JSAPITreeMap::Clear(thread, JSHandle<JSAPITreeMap>::Cast(self));
292     return JSTaggedValue::Undefined();
293 }
294 
GetLowerKey(EcmaRuntimeCallInfo * argv)295 JSTaggedValue ContainersTreeMap::GetLowerKey(EcmaRuntimeCallInfo *argv)
296 {
297     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLowerKey);
298     JSThread *thread = argv->GetThread();
299     [[maybe_unused]] EcmaHandleScope handleScope(thread);
300     // get and check this map
301     JSHandle<JSTaggedValue> self(GetThis(argv));
302     if (!self->IsJSAPITreeMap()) {
303         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
304             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
305         } else {
306             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
307                                                                 "The getLowerKey method cannot be bound");
308             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
309         }
310     }
311 
312     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
313     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
314 
315     JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
316     return TaggedTreeMap::GetLowerKey(thread, tmap, key);
317 }
318 
GetHigherKey(EcmaRuntimeCallInfo * argv)319 JSTaggedValue ContainersTreeMap::GetHigherKey(EcmaRuntimeCallInfo *argv)
320 {
321     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetHigherKey);
322     JSThread *thread = argv->GetThread();
323     [[maybe_unused]] EcmaHandleScope handleScope(thread);
324     // get and check this map
325     JSHandle<JSTaggedValue> self(GetThis(argv));
326     if (!self->IsJSAPITreeMap()) {
327         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
328             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
329         } else {
330             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
331                                                                 "The getHigherKey method cannot be bound");
332             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
333         }
334     }
335 
336     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
337     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
338 
339     JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
340     return TaggedTreeMap::GetHigherKey(thread, tmap, key);
341 }
342 
Replace(EcmaRuntimeCallInfo * argv)343 JSTaggedValue ContainersTreeMap::Replace(EcmaRuntimeCallInfo *argv)
344 {
345     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Replace);
346     JSThread *thread = argv->GetThread();
347     [[maybe_unused]] EcmaHandleScope handleScope(thread);
348     // get and check this map
349     JSHandle<JSTaggedValue> self(GetThis(argv));
350     if (!self->IsJSAPITreeMap()) {
351         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
352             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
353         } else {
354             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
355                                                                 "The replace method cannot be bound");
356             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
357         }
358     }
359 
360     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
361     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
362     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
363 
364     bool success = JSAPITreeMap::Replace(thread, map, key, value);
365     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
366     return GetTaggedBoolean(success);
367 }
368 
Keys(EcmaRuntimeCallInfo * argv)369 JSTaggedValue ContainersTreeMap::Keys(EcmaRuntimeCallInfo *argv)
370 {
371     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Keys);
372     JSThread *thread = argv->GetThread();
373     [[maybe_unused]] EcmaHandleScope handleScope(thread);
374     JSHandle<JSTaggedValue> self = GetThis(argv);
375     JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY);
376     return iter.GetTaggedValue();
377 }
378 
Values(EcmaRuntimeCallInfo * argv)379 JSTaggedValue ContainersTreeMap::Values(EcmaRuntimeCallInfo *argv)
380 {
381     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Values);
382     JSThread *thread = argv->GetThread();
383     [[maybe_unused]] EcmaHandleScope handleScope(thread);
384     JSHandle<JSTaggedValue> self = GetThis(argv);
385     JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::VALUE);
386     return iter.GetTaggedValue();
387 }
388 
Entries(EcmaRuntimeCallInfo * argv)389 JSTaggedValue ContainersTreeMap::Entries(EcmaRuntimeCallInfo *argv)
390 {
391     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Entries);
392     JSThread *thread = argv->GetThread();
393     [[maybe_unused]] EcmaHandleScope handleScope(thread);
394     JSHandle<JSTaggedValue> self = GetThis(argv);
395     JSHandle<JSTaggedValue> iter =
396         JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
397     return iter.GetTaggedValue();
398 }
399 
ForEach(EcmaRuntimeCallInfo * argv)400 JSTaggedValue ContainersTreeMap::ForEach(EcmaRuntimeCallInfo *argv)
401 {
402     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, ForEach);
403     JSThread *thread = argv->GetThread();
404     [[maybe_unused]] EcmaHandleScope handleScope(thread);
405     // get and check TreeMap object
406     JSHandle<JSTaggedValue> self = GetThis(argv);
407     if (!self->IsJSAPITreeMap()) {
408         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
409             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
410         } else {
411             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
412                                                                 "The rorEach method cannot be bound");
413             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
414         }
415     }
416     // get and check callback function
417     JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
418     if (!func->IsCallable()) {
419         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
420         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
421         CString errorMsg =
422             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
423         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
424         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
425     }
426     // If thisArg was supplied, let T be thisArg; else let T be undefined.
427     JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
428     JSHandle<JSAPITreeMap> tmap = JSHandle<JSAPITreeMap>::Cast(self);
429     JSMutableHandle<TaggedTreeMap> iteratedMap(thread, tmap->GetTreeMap());
430     uint32_t elements = iteratedMap->NumberOfElements();
431     JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
432     uint32_t index = 0;
433     size_t length = entries->GetLength();
434     const uint32_t argsLength = 3;
435     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
436     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
437     JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
438     while (index < elements) {
439         int entriesIndex = entries->Get(index).GetInt();
440         key.Update(iteratedMap->GetKey(entriesIndex));
441         value.Update(iteratedMap->GetValue(entriesIndex));
442         // Let funcResult be Call(callbackfn, T, «e, e, S»).
443         EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
444         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
445         info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue());
446         JSTaggedValue ret = JSFunction::Call(info);
447         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
448         // check entries should be update, size will be update in tmap set or remove.
449         if (tmap->GetSize() != static_cast<int>(length)) {
450             iteratedMap.Update(tmap->GetTreeMap());
451             entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
452             elements = iteratedMap->NumberOfElements();
453             length = entries->GetLength();
454         }
455         index++;
456     }
457     return JSTaggedValue::Undefined();
458 }
459 
GetLength(EcmaRuntimeCallInfo * argv)460 JSTaggedValue ContainersTreeMap::GetLength(EcmaRuntimeCallInfo *argv)
461 {
462     ASSERT(argv);
463     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLength);
464     JSThread *thread = argv->GetThread();
465     [[maybe_unused]] EcmaHandleScope handleScope(thread);
466     // get and check this map
467     JSHandle<JSTaggedValue> self(GetThis(argv));
468     if (!self->IsJSAPITreeMap()) {
469         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
470             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
471         } else {
472             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
473                                                                 "The getLength method cannot be bound");
474             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
475         }
476     }
477     int count = JSHandle<JSAPITreeMap>::Cast(self)->GetSize();
478     return JSTaggedValue(count);
479 }
480 
IsEmpty(EcmaRuntimeCallInfo * argv)481 JSTaggedValue ContainersTreeMap::IsEmpty(EcmaRuntimeCallInfo *argv)
482 {
483     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, IsEmpty);
484     JSThread *thread = argv->GetThread();
485     [[maybe_unused]] EcmaHandleScope handleScope(thread);
486     // get and check this map
487     JSHandle<JSTaggedValue> self = GetThis(argv);
488     if (!self->IsJSAPITreeMap()) {
489         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
490             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
491         } else {
492             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
493                                                                 "The isEmpty method cannot be bound");
494             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
495         }
496     }
497     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
498     return GetTaggedBoolean(map->GetSize() == 0);
499 }
500 }  // namespace panda::ecmascript::containers
501