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