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 "containers_hashmap.h"
17
18#include "ecmascript/containers/containers_errors.h"
19#include "ecmascript/interpreter/interpreter.h"
20#include "ecmascript/js_api/js_api_hashmap_iterator.h"
21#include "ecmascript/js_function.h"
22
23namespace panda::ecmascript::containers {
24JSTaggedValue ContainersHashMap::HashMapConstructor(EcmaRuntimeCallInfo *argv)
25{
26    ASSERT(argv != nullptr);
27    JSThread *thread = argv->GetThread();
28    BUILTINS_API_TRACE(thread, HashMap, Constructor);
29    [[maybe_unused]] EcmaHandleScope handleScope(thread);
30    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
31
32    JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33    if (newTarget->IsUndefined()) {
34        JSTaggedValue error =
35            ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
36                                          "The HashMap's constructor cannot be directly invoked");
37        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
38    }
39
40    JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
41    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
42    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
43
44    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(obj);
45    JSTaggedValue hashMapArray = TaggedHashArray::Create(thread);
46    hashMap->SetTable(thread, hashMapArray);
47    hashMap->SetSize(0);
48
49    return hashMap.GetTaggedValue();
50}
51
52JSTaggedValue ContainersHashMap::Keys(EcmaRuntimeCallInfo *argv)
53{
54    ASSERT(argv != nullptr);
55    JSThread *thread = argv->GetThread();
56    BUILTINS_API_TRACE(thread, HashMap, Keys);
57    [[maybe_unused]] EcmaHandleScope handleScope(thread);
58    JSHandle<JSTaggedValue> self = GetThis(argv);
59    if (!self->IsJSAPIHashMap()) {
60        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
61            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
62        } else {
63            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
64                                                                "The keys method cannot be bound");
65            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
66        }
67    }
68    JSHandle<JSTaggedValue> iter =
69        JSAPIHashMapIterator::CreateHashMapIterator(thread, self, IterationKind::KEY);
70    return iter.GetTaggedValue();
71}
72
73JSTaggedValue ContainersHashMap::Values(EcmaRuntimeCallInfo *argv)
74{
75    ASSERT(argv != nullptr);
76    JSThread *thread = argv->GetThread();
77    BUILTINS_API_TRACE(thread, HashMap, Values);
78    [[maybe_unused]] EcmaHandleScope handleScope(thread);
79    JSHandle<JSTaggedValue> self = GetThis(argv);
80    if (!self->IsJSAPIHashMap()) {
81        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
82            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
83        } else {
84            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
85                                                                "The values method cannot be bound");
86            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
87        }
88    }
89    JSHandle<JSTaggedValue> iter =
90        JSAPIHashMapIterator::CreateHashMapIterator(thread, self, IterationKind::VALUE);
91    return iter.GetTaggedValue();
92}
93
94JSTaggedValue ContainersHashMap::GetIteratorObj(EcmaRuntimeCallInfo *argv)
95{
96    ASSERT(argv != nullptr);
97    JSThread *thread = argv->GetThread();
98    BUILTINS_API_TRACE(thread, HashMap, GetIteratorObj);
99    [[maybe_unused]] EcmaHandleScope handleScope(thread);
100    JSHandle<JSTaggedValue> self = GetThis(argv);
101    if (!self->IsJSAPIHashMap()) {
102        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
103            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
104        } else {
105            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
106                                                                "The Symbol.iterator method cannot be bound");
107            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
108        }
109    }
110    JSHandle<JSTaggedValue> iter =
111        JSAPIHashMapIterator::CreateHashMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
112    return iter.GetTaggedValue();
113}
114
115JSTaggedValue ContainersHashMap::Entries(EcmaRuntimeCallInfo *argv)
116{
117    ASSERT(argv != nullptr);
118    JSThread *thread = argv->GetThread();
119    BUILTINS_API_TRACE(thread, HashMap, Entries);
120    [[maybe_unused]] EcmaHandleScope handleScope(thread);
121    JSHandle<JSTaggedValue> self = GetThis(argv);
122    if (!self->IsJSAPIHashMap()) {
123        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
124            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
125        } else {
126            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
127                                                                "The entries method cannot be bound");
128            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
129        }
130    }
131    JSHandle<JSTaggedValue> iter =
132        JSAPIHashMapIterator::CreateHashMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
133    return iter.GetTaggedValue();
134}
135
136JSTaggedValue ContainersHashMap::ForEach(EcmaRuntimeCallInfo *argv)
137{
138    ASSERT(argv != nullptr);
139    JSThread *thread = argv->GetThread();
140    BUILTINS_API_TRACE(thread, HashMap, ForEach);
141    [[maybe_unused]] EcmaHandleScope handleScope(thread);
142    JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
143    if (!thisHandle->IsJSAPIHashMap()) {
144        if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIHashMap()) {
145            thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
146        } else {
147            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
148                                                                "The forEach method cannot be bound");
149            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
150        }
151    }
152    JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
153    if (!callbackFnHandle->IsCallable()) {
154        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
155        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
156        CString errorMsg =
157            "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
158        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
159        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
160    }
161    JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
162    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(thisHandle);
163    JSHandle<TaggedHashArray> table(thread, hashMap->GetTable());
164    uint32_t len = table->GetLength();
165    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
166    JSMutableHandle<TaggedQueue> queue(thread, factory->NewTaggedQueue(0));
167    JSMutableHandle<TaggedNode> node(thread, JSTaggedValue::Undefined());
168    JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
169    JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
170    uint32_t index = 0;
171    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
172    while (index < len) {
173        node.Update(TaggedHashArray::GetCurrentNode(thread, queue, table, index));
174        if (!node.GetTaggedValue().IsHole()) {
175            key.Update(node->GetKey());
176            value.Update(node->GetValue());
177            EcmaRuntimeCallInfo *info =
178                EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle,
179                                                    thisArgHandle, undefined, 3); // 3: three args
180            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
181            info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue());
182            JSTaggedValue funcResult = JSFunction::Call(info);
183            RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
184        }
185    }
186    return JSTaggedValue::Undefined();
187}
188
189JSTaggedValue ContainersHashMap::Set(EcmaRuntimeCallInfo *argv)
190{
191    ASSERT(argv != nullptr);
192    JSThread *thread = argv->GetThread();
193    BUILTINS_API_TRACE(thread, HashMap, Set);
194    [[maybe_unused]] EcmaHandleScope handleScope(thread);
195    JSHandle<JSTaggedValue> self = GetThis(argv);
196    if (!self->IsJSAPIHashMap()) {
197        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
198            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
199        } else {
200            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
201                                                                "The set method cannot be bound");
202            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
203        }
204    }
205    JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
206    JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
207    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(self);
208    JSAPIHashMap::Set(thread, hashMap, key, value);
209    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
210    return hashMap.GetTaggedValue();
211}
212
213JSTaggedValue ContainersHashMap::SetAll(EcmaRuntimeCallInfo *argv)
214{
215    ASSERT(argv != nullptr);
216    JSThread *thread = argv->GetThread();
217    BUILTINS_API_TRACE(thread, HashMap, SetAll);
218    [[maybe_unused]] EcmaHandleScope handleScope(thread);
219    JSHandle<JSTaggedValue> self = GetThis(argv);
220    if (!self->IsJSAPIHashMap()) {
221        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
222            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
223        } else {
224            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
225                                                                "The setAll method cannot be bound");
226            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227        }
228    }
229
230    JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
231    if (!obj->IsJSAPIHashMap()) {
232        if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPIHashMap()) {
233            obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
234        } else {
235            JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj);
236            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
237            CString errorMsg =
238                "The type of \"map\" must be HashMap. Received value is: " + ConvertToString(*result);
239            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
240            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
241        }
242    }
243
244    JSHandle<JSAPIHashMap> targetMap = JSHandle<JSAPIHashMap>::Cast(self);
245    JSHandle<JSAPIHashMap> sourceMap = JSHandle<JSAPIHashMap>::Cast(obj);
246    JSAPIHashMap::SetAll(thread, targetMap, sourceMap);
247    return self.GetTaggedValue();
248}
249
250JSTaggedValue ContainersHashMap::Get(EcmaRuntimeCallInfo *argv)
251{
252    ASSERT(argv != nullptr);
253    JSThread *thread = argv->GetThread();
254    BUILTINS_API_TRACE(thread, HashMap, Get);
255    [[maybe_unused]] EcmaHandleScope handleScope(thread);
256    JSHandle<JSTaggedValue> self = GetThis(argv);
257    if (!self->IsJSAPIHashMap()) {
258        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
259            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
260        } else {
261            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
262                                                                "The get method cannot be bound");
263            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
264        }
265    }
266    JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
267    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(self);
268    return hashMap->Get(thread, key.GetTaggedValue());
269}
270
271JSTaggedValue ContainersHashMap::Remove(EcmaRuntimeCallInfo *argv)
272{
273    ASSERT(argv != nullptr);
274    JSThread *thread = argv->GetThread();
275    BUILTINS_API_TRACE(thread, HashMap, Remove);
276    [[maybe_unused]] EcmaHandleScope handleScope(thread);
277    JSHandle<JSTaggedValue> self = GetThis(argv);
278
279    if (!self->IsJSAPIHashMap()) {
280        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
281            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
282        } else {
283            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
284                                                                "The remove method cannot be bound");
285            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
286        }
287    }
288    JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
289    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(self);
290    return JSAPIHashMap::Remove(thread, hashMap, key.GetTaggedValue());
291}
292
293JSTaggedValue ContainersHashMap::HasKey(EcmaRuntimeCallInfo *argv)
294{
295    ASSERT(argv != nullptr);
296    JSThread *thread = argv->GetThread();
297    BUILTINS_API_TRACE(thread, HashMap, HasKey);
298    [[maybe_unused]] EcmaHandleScope handleScope(thread);
299    JSHandle<JSTaggedValue> self = GetThis(argv);
300
301    if (!self->IsJSAPIHashMap()) {
302        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
303            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
304        } else {
305            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
306                                                                "The hasKey method cannot be bound");
307            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
308        }
309    }
310    JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
311    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(self);
312    return hashMap->HasKey(thread, key.GetTaggedValue());
313}
314
315JSTaggedValue ContainersHashMap::HasValue(EcmaRuntimeCallInfo *argv)
316{
317    ASSERT(argv != nullptr);
318    JSThread *thread = argv->GetThread();
319    BUILTINS_API_TRACE(thread, HashMap, HasValue);
320    [[maybe_unused]] EcmaHandleScope handleScope(thread);
321    JSHandle<JSTaggedValue> self = GetThis(argv);
322
323    if (!self->IsJSAPIHashMap()) {
324        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
325            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
326        } else {
327            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
328                                                                "The hasValue method cannot be bound");
329            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
330        }
331    }
332    JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
333    JSHandle<JSAPIHashMap> hashMap = JSHandle<JSAPIHashMap>::Cast(self);
334    return JSAPIHashMap::HasValue(thread, hashMap, value);
335}
336
337JSTaggedValue ContainersHashMap::Replace(EcmaRuntimeCallInfo *argv)
338{
339    ASSERT(argv != nullptr);
340    JSThread *thread = argv->GetThread();
341    BUILTINS_API_TRACE(thread, HashMap, Replace);
342    [[maybe_unused]] EcmaHandleScope handleScope(thread);
343    JSHandle<JSTaggedValue> self = GetThis(argv);
344    if (!self->IsJSAPIHashMap()) {
345        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
346            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
347        } else {
348            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
349                                                                "The replace method cannot be bound");
350            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
351        }
352    }
353    JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
354    JSHandle<JSTaggedValue> newValue = GetCallArg(argv, 1);
355    JSHandle<JSAPIHashMap> jsHashMap = JSHandle<JSAPIHashMap>::Cast(self);
356    return JSTaggedValue(jsHashMap->Replace(thread, key.GetTaggedValue(), newValue.GetTaggedValue()));
357}
358
359JSTaggedValue ContainersHashMap::Clear(EcmaRuntimeCallInfo *argv)
360{
361    ASSERT(argv != nullptr);
362    JSThread *thread = argv->GetThread();
363    BUILTINS_API_TRACE(thread, HashMap, Clear);
364    [[maybe_unused]] EcmaHandleScope handleScope(thread);
365    JSHandle<JSTaggedValue> self = GetThis(argv);
366    if (!self->IsJSAPIHashMap()) {
367        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
368            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
369        } else {
370            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
371                                                                "The clear method cannot be bound");
372            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
373        }
374    }
375    JSHandle<JSAPIHashMap> jsHashMap = JSHandle<JSAPIHashMap>::Cast(self);
376    jsHashMap->Clear(thread);
377    return JSTaggedValue::Undefined();
378}
379
380JSTaggedValue ContainersHashMap::GetLength(EcmaRuntimeCallInfo *argv)
381{
382    ASSERT(argv != nullptr);
383    JSThread *thread = argv->GetThread();
384    BUILTINS_API_TRACE(thread, HashMap, GetLength);
385    [[maybe_unused]] EcmaHandleScope handleScope(thread);
386    JSHandle<JSTaggedValue> self = GetThis(argv);
387    if (!self->IsJSAPIHashMap()) {
388        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
389            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
390        } else {
391            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
392                                                                "The getLength method cannot be bound");
393            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
394        }
395    }
396    JSHandle<JSAPIHashMap> jsHashMap = JSHandle<JSAPIHashMap>::Cast(self);
397    return jsHashMap->GetLength();
398}
399
400JSTaggedValue ContainersHashMap::IsEmpty(EcmaRuntimeCallInfo *argv)
401{
402    ASSERT(argv != nullptr);
403    JSThread *thread = argv->GetThread();
404    BUILTINS_API_TRACE(thread, HashMap, IsEmpty);
405    [[maybe_unused]] EcmaHandleScope handleScope(thread);
406    JSHandle<JSTaggedValue> self = GetThis(argv);
407    if (!self->IsJSAPIHashMap()) {
408        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIHashMap()) {
409            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
410        } else {
411            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
412                                                                "The isEmpty method cannot be bound");
413            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
414        }
415    }
416    JSHandle<JSAPIHashMap> jsHashMap = JSHandle<JSAPIHashMap>::Cast(self);
417    return jsHashMap->IsEmpty();
418}
419} // namespace panda::ecmascript::containers
420