• 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/tagged_tree.h"
24 
25 namespace panda::ecmascript::containers {
TreeMapConstructor(EcmaRuntimeCallInfo * argv)26 JSTaggedValue ContainersTreeMap::TreeMapConstructor(EcmaRuntimeCallInfo *argv)
27 {
28     ASSERT(argv);
29     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Constructor);
30     JSThread *thread = argv->GetThread();
31     [[maybe_unused]] EcmaHandleScope handleScope(thread);
32     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33 
34     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
35     if (newTarget->IsUndefined()) {
36         JSTaggedValue error =
37             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
38                                           "The TreeMap's constructor cannot be directly invoked");
39         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
40     }
41 
42     // new TreeMap
43     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
44     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
45     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
46 
47     // Set map’s internal slot with a new empty List.
48     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(obj);
49     JSTaggedValue internal = TaggedTreeMap::Create(thread);
50     map->SetTreeMap(thread, internal);
51 
52     // If comparefn was supplied, let compare be comparefn; else let compare be hole.
53     JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
54     if (compareFn->IsUndefined() || compareFn->IsNull()) {
55         return map.GetTaggedValue();
56     }
57     if (!compareFn->IsCallable()) {
58         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue());
59         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
60         CString errorMsg =
61             "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
62         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
63         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
64     }
65 
66     TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
67     return map.GetTaggedValue();
68 }
69 
Set(EcmaRuntimeCallInfo * argv)70 JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv)
71 {
72     ASSERT(argv);
73     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set);
74     JSThread *thread = argv->GetThread();
75     [[maybe_unused]] EcmaHandleScope handleScope(thread);
76     JSHandle<JSTaggedValue> self = GetThis(argv);
77     // get and check this map
78     if (!self->IsJSAPITreeMap()) {
79         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
80             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
81         } else {
82             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
83                                                                 "The set method cannot be bound");
84             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
85         }
86     }
87 
88     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
89     JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
90 
91     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
92     JSAPITreeMap::Set(thread, map, key, value);
93     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
94     return map.GetTaggedValue();
95 }
96 
Get(EcmaRuntimeCallInfo * argv)97 JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv)
98 {
99     ASSERT(argv);
100     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get);
101     JSThread *thread = argv->GetThread();
102     [[maybe_unused]] EcmaHandleScope handleScope(thread);
103     // get and check this map
104     JSHandle<JSTaggedValue> self(GetThis(argv));
105     if (!self->IsJSAPITreeMap()) {
106         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
107             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
108         } else {
109             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
110                                                                 "The get method cannot be bound");
111             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
112         }
113     }
114 
115     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
116     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
117     return JSAPITreeMap::Get(thread, map, key);
118 }
119 
Remove(EcmaRuntimeCallInfo * argv)120 JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv)
121 {
122     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove);
123     JSThread *thread = argv->GetThread();
124     [[maybe_unused]] EcmaHandleScope handleScope(thread);
125     JSHandle<JSTaggedValue> self = GetThis(argv);
126     // get and check this map
127     if (!self->IsJSAPITreeMap()) {
128         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
129             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
130         } else {
131             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
132                                                                 "The remove method cannot be bound");
133             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
134         }
135     }
136 
137     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
138     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
139     return JSAPITreeMap::Delete(thread, map, key);
140 }
141 
HasKey(EcmaRuntimeCallInfo * argv)142 JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv)
143 {
144     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey);
145     JSThread *thread = argv->GetThread();
146     [[maybe_unused]] EcmaHandleScope handleScope(thread);
147     // get and check this map
148     JSHandle<JSTaggedValue> self(GetThis(argv));
149     if (!self->IsJSAPITreeMap()) {
150         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
151             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
152         } else {
153             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
154                                                                 "The hasKey method cannot be bound");
155             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
156         }
157     }
158 
159     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
160     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
161 
162     bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key);
163     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
164     return GetTaggedBoolean(flag);
165 }
166 
HasValue(EcmaRuntimeCallInfo * argv)167 JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv)
168 {
169     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue);
170     JSThread *thread = argv->GetThread();
171     [[maybe_unused]] EcmaHandleScope handleScope(thread);
172     // get and check this map
173     JSHandle<JSTaggedValue> self(GetThis(argv));
174     if (!self->IsJSAPITreeMap()) {
175         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
176             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
177         } else {
178             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
179                                                                 "The hasValue method cannot be bound");
180             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
181         }
182     }
183 
184     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
185     bool flag = map->HasValue(thread, GetCallArg(argv, 0));
186     return GetTaggedBoolean(flag);
187 }
188 
GetFirstKey(EcmaRuntimeCallInfo * argv)189 JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv)
190 {
191     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey);
192     JSThread *thread = argv->GetThread();
193     [[maybe_unused]] EcmaHandleScope handleScope(thread);
194     // get and check this map
195     JSHandle<JSTaggedValue> self(GetThis(argv));
196     if (!self->IsJSAPITreeMap()) {
197         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
198             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
199         } else {
200             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
201                                                                 "The getFirstKey method cannot be bound");
202             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
203         }
204     }
205 
206     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
207     return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey();
208 }
209 
GetLastKey(EcmaRuntimeCallInfo * argv)210 JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv)
211 {
212     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey);
213     JSThread *thread = argv->GetThread();
214     [[maybe_unused]] EcmaHandleScope handleScope(thread);
215     // get and check this map
216     JSHandle<JSTaggedValue> self(GetThis(argv));
217     if (!self->IsJSAPITreeMap()) {
218         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
219             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
220         } else {
221             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
222                                                                 "The getLastKey method cannot be bound");
223             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
224         }
225     }
226 
227     JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
228     return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey();
229 }
230 
SetAll(EcmaRuntimeCallInfo * argv)231 JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv)
232 {
233     BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll);
234     JSThread *thread = argv->GetThread();
235     [[maybe_unused]] EcmaHandleScope handleScope(thread);
236     // get and check this map
237     JSHandle<JSTaggedValue> self(GetThis(argv));
238     if (!self->IsJSAPITreeMap()) {
239         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
240             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
241         } else {
242             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
243                                                                 "The setAll method cannot be bound");
244             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
245         }
246     }
247 
248     JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
249     if (!obj->IsJSAPITreeMap()) {
250         if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) {
251             obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
252         } else {
253             JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue());
254             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
255             CString errorMsg =
256                 "The type of \"map\" must be TreeMap. Received value is: " + ConvertToString(*result);
257             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
258             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
259         }
260     }
261 
262     JSHandle<JSAPITreeMap> dst = JSHandle<JSAPITreeMap>::Cast(self);
263     JSHandle<TaggedTreeMap> dmap(thread, dst->GetTreeMap());
264     JSHandle<TaggedTreeMap> smap(thread, JSHandle<JSAPITreeMap>::Cast(obj)->GetTreeMap());
265 
266     if (JSHandle<JSAPITreeMap>::Cast(obj)->GetSize() > 0) {
267         JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
268         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
269         dst->SetTreeMap(thread, tmap);
270     }
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 forEach 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