• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/containers/containers_treemap.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_tree_map.h"
21 #include "ecmascript/js_api/js_api_tree_map_iterator.h"
22 #include "ecmascript/js_function.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     if (JSHandle<JSAPITreeMap>::Cast(obj)->GetSize() > 0) {
269         JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
270         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
271         dst->SetTreeMap(thread, tmap);
272     }
273     return JSTaggedValue::Undefined();
274 }
275 
Clear(EcmaRuntimeCallInfo * argv)276 JSTaggedValue ContainersTreeMap::Clear(EcmaRuntimeCallInfo *argv)
277 {
278     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Clear);
279     JSThread *thread = argv->GetThread();
280     [[maybe_unused]] EcmaHandleScope handleScope(thread);
281     // get and check this map
282     JSHandle<JSTaggedValue> self(GetThis(argv));
283     if (!self->IsJSAPITreeMap()) {
284         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
285             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
286         } else {
287             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
288                                                                 "The clear method cannot be bound");
289             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
290         }
291     }
292 
293     JSAPITreeMap::Clear(thread, JSHandle<JSAPITreeMap>::Cast(self));
294     return JSTaggedValue::Undefined();
295 }
296 
GetLowerKey(EcmaRuntimeCallInfo * argv)297 JSTaggedValue ContainersTreeMap::GetLowerKey(EcmaRuntimeCallInfo *argv)
298 {
299     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLowerKey);
300     JSThread *thread = argv->GetThread();
301     [[maybe_unused]] EcmaHandleScope handleScope(thread);
302     // get and check this map
303     JSHandle<JSTaggedValue> self(GetThis(argv));
304     if (!self->IsJSAPITreeMap()) {
305         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
306             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
307         } else {
308             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
309                                                                 "The getLowerKey method cannot be bound");
310             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
311         }
312     }
313 
314     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
315     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
316 
317     JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
318     return TaggedTreeMap::GetLowerKey(thread, tmap, key);
319 }
320 
GetHigherKey(EcmaRuntimeCallInfo * argv)321 JSTaggedValue ContainersTreeMap::GetHigherKey(EcmaRuntimeCallInfo *argv)
322 {
323     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetHigherKey);
324     JSThread *thread = argv->GetThread();
325     [[maybe_unused]] EcmaHandleScope handleScope(thread);
326     // get and check this map
327     JSHandle<JSTaggedValue> self(GetThis(argv));
328     if (!self->IsJSAPITreeMap()) {
329         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
330             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
331         } else {
332             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
333                                                                 "The getHigherKey method cannot be bound");
334             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
335         }
336     }
337 
338     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
339     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
340 
341     JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
342     return TaggedTreeMap::GetHigherKey(thread, tmap, key);
343 }
344 
Replace(EcmaRuntimeCallInfo * argv)345 JSTaggedValue ContainersTreeMap::Replace(EcmaRuntimeCallInfo *argv)
346 {
347     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Replace);
348     JSThread *thread = argv->GetThread();
349     [[maybe_unused]] EcmaHandleScope handleScope(thread);
350     // get and check this map
351     JSHandle<JSTaggedValue> self(GetThis(argv));
352     if (!self->IsJSAPITreeMap()) {
353         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
354             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
355         } else {
356             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
357                                                                 "The replace method cannot be bound");
358             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
359         }
360     }
361 
362     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
363     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
364     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
365 
366     bool success = JSAPITreeMap::Replace(thread, map, key, value);
367     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
368     return GetTaggedBoolean(success);
369 }
370 
Keys(EcmaRuntimeCallInfo * argv)371 JSTaggedValue ContainersTreeMap::Keys(EcmaRuntimeCallInfo *argv)
372 {
373     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Keys);
374     JSThread *thread = argv->GetThread();
375     [[maybe_unused]] EcmaHandleScope handleScope(thread);
376     JSHandle<JSTaggedValue> self = GetThis(argv);
377     JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY);
378     return iter.GetTaggedValue();
379 }
380 
Values(EcmaRuntimeCallInfo * argv)381 JSTaggedValue ContainersTreeMap::Values(EcmaRuntimeCallInfo *argv)
382 {
383     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Values);
384     JSThread *thread = argv->GetThread();
385     [[maybe_unused]] EcmaHandleScope handleScope(thread);
386     JSHandle<JSTaggedValue> self = GetThis(argv);
387     JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::VALUE);
388     return iter.GetTaggedValue();
389 }
390 
Entries(EcmaRuntimeCallInfo * argv)391 JSTaggedValue ContainersTreeMap::Entries(EcmaRuntimeCallInfo *argv)
392 {
393     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Entries);
394     JSThread *thread = argv->GetThread();
395     [[maybe_unused]] EcmaHandleScope handleScope(thread);
396     JSHandle<JSTaggedValue> self = GetThis(argv);
397     JSHandle<JSTaggedValue> iter =
398         JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
399     return iter.GetTaggedValue();
400 }
401 
ForEach(EcmaRuntimeCallInfo * argv)402 JSTaggedValue ContainersTreeMap::ForEach(EcmaRuntimeCallInfo *argv)
403 {
404     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, ForEach);
405     JSThread *thread = argv->GetThread();
406     [[maybe_unused]] EcmaHandleScope handleScope(thread);
407     // get and check TreeMap object
408     JSHandle<JSTaggedValue> self = GetThis(argv);
409     if (!self->IsJSAPITreeMap()) {
410         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
411             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
412         } else {
413             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
414                                                                 "The forEach method cannot be bound");
415             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
416         }
417     }
418     // get and check callback function
419     JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
420     if (!func->IsCallable()) {
421         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
422         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
423         CString errorMsg =
424             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
425         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
426         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
427     }
428     // If thisArg was supplied, let T be thisArg; else let T be undefined.
429     JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
430     JSHandle<JSAPITreeMap> tmap = JSHandle<JSAPITreeMap>::Cast(self);
431     JSMutableHandle<TaggedTreeMap> iteratedMap(thread, tmap->GetTreeMap());
432     uint32_t elements = iteratedMap->NumberOfElements();
433     JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
434     uint32_t index = 0;
435     size_t length = entries->GetLength();
436     const uint32_t argsLength = 3;
437     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
438     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
439     JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
440     while (index < elements) {
441         int entriesIndex = entries->Get(index).GetInt();
442         key.Update(iteratedMap->GetKey(entriesIndex));
443         value.Update(iteratedMap->GetValue(entriesIndex));
444         // Let funcResult be Call(callbackfn, T, «e, e, S»).
445         EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
446         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
447         info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue());
448         JSTaggedValue ret = JSFunction::Call(info);
449         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
450         // check entries should be update, size will be update in tmap set or remove.
451         if (tmap->GetSize() != static_cast<int>(length)) {
452             iteratedMap.Update(tmap->GetTreeMap());
453             entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
454             elements = iteratedMap->NumberOfElements();
455             length = entries->GetLength();
456         }
457         index++;
458     }
459     return JSTaggedValue::Undefined();
460 }
461 
GetLength(EcmaRuntimeCallInfo * argv)462 JSTaggedValue ContainersTreeMap::GetLength(EcmaRuntimeCallInfo *argv)
463 {
464     ASSERT(argv);
465     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLength);
466     JSThread *thread = argv->GetThread();
467     [[maybe_unused]] EcmaHandleScope handleScope(thread);
468     // get and check this map
469     JSHandle<JSTaggedValue> self(GetThis(argv));
470     if (!self->IsJSAPITreeMap()) {
471         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
472             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
473         } else {
474             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
475                                                                 "The getLength method cannot be bound");
476             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
477         }
478     }
479     int count = JSHandle<JSAPITreeMap>::Cast(self)->GetSize();
480     return JSTaggedValue(count);
481 }
482 
IsEmpty(EcmaRuntimeCallInfo * argv)483 JSTaggedValue ContainersTreeMap::IsEmpty(EcmaRuntimeCallInfo *argv)
484 {
485     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, IsEmpty);
486     JSThread *thread = argv->GetThread();
487     [[maybe_unused]] EcmaHandleScope handleScope(thread);
488     // get and check this map
489     JSHandle<JSTaggedValue> self = GetThis(argv);
490     if (!self->IsJSAPITreeMap()) {
491         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
492             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
493         } else {
494             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
495                                                                 "The isEmpty method cannot be bound");
496             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
497         }
498     }
499     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
500     return GetTaggedBoolean(map->GetSize() == 0);
501 }
502 }  // namespace panda::ecmascript::containers
503