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