• 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_lightweightmap.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_lightweightmap.h"
21 #include "ecmascript/js_api/js_api_lightweightmap_iterator.h"
22 #include "ecmascript/js_function.h"
23 
24 namespace panda::ecmascript::containers {
LightWeightMapConstructor(EcmaRuntimeCallInfo * argv)25 JSTaggedValue ContainersLightWeightMap::LightWeightMapConstructor(EcmaRuntimeCallInfo *argv)
26 {
27     ASSERT(argv != nullptr);
28     JSThread *thread = argv->GetThread();
29     BUILTINS_API_TRACE(thread, LightWeightMap, Constructor);
30     [[maybe_unused]] EcmaHandleScope handleScope(thread);
31     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33     if (newTarget->IsUndefined()) {
34         JSTaggedValue error =
35             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
36                                           "The LightWeightMap's constructor cannot be directly invoked");
37         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
38     }
39     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
40     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
41     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42     JSHandle<JSAPILightWeightMap> lwMap = JSHandle<JSAPILightWeightMap>::Cast(obj);
43     JSHandle<TaggedArray> hashArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
44     JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
45     JSHandle<TaggedArray> valueArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
46     lwMap->SetHashes(thread, hashArray.GetTaggedValue());
47     lwMap->SetKeys(thread, keyArray.GetTaggedValue());
48     lwMap->SetValues(thread, valueArray.GetTaggedValue());
49 
50     return lwMap.GetTaggedValue();
51 }
52 
Length(EcmaRuntimeCallInfo * argv)53 JSTaggedValue ContainersLightWeightMap::Length(EcmaRuntimeCallInfo *argv)
54 {
55     ASSERT(argv != nullptr);
56     JSThread *thread = argv->GetThread();
57     BUILTINS_API_TRACE(thread, LightWeightMap, Length);
58     [[maybe_unused]] EcmaHandleScope handleScope(thread);
59     JSHandle<JSTaggedValue> self = GetThis(argv);
60 
61     if (!self->IsJSAPILightWeightMap()) {
62         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
63             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
64         } else {
65             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
66                                                                 "The getLength method cannot be bound");
67             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
68         }
69     }
70 
71     return JSTaggedValue(JSHandle<JSAPILightWeightMap>::Cast(self)->GetLength());
72 }
73 
HasAll(EcmaRuntimeCallInfo * argv)74 JSTaggedValue ContainersLightWeightMap::HasAll(EcmaRuntimeCallInfo *argv)
75 {
76     ASSERT(argv != nullptr);
77     JSThread *thread = argv->GetThread();
78     BUILTINS_API_TRACE(thread, LightWeightMap, HasAll);
79     [[maybe_unused]] EcmaHandleScope handleScope(thread);
80     JSHandle<JSTaggedValue> self = GetThis(argv);
81 
82     if (!self->IsJSAPILightWeightMap()) {
83         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
84             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
85         } else {
86             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
87                                                                 "The hasAll method cannot be bound");
88             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
89         }
90     }
91 
92     JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0));
93     if (!lightWeightMap->IsJSAPILightWeightMap()) {
94         if (lightWeightMap->IsJSProxy() &&
95             JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) {
96             lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget());
97         } else {
98             JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue());
99             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
100             CString errorMsg =
101                 "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result);
102             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
103             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
104         }
105     }
106 
107     return JSAPILightWeightMap::HasAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
108                                        JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap));
109 }
110 
HasKey(EcmaRuntimeCallInfo * argv)111 JSTaggedValue ContainersLightWeightMap::HasKey(EcmaRuntimeCallInfo *argv)
112 {
113     ASSERT(argv != nullptr);
114     JSThread *thread = argv->GetThread();
115     BUILTINS_API_TRACE(thread, LightWeightMap, HasKey);
116     [[maybe_unused]] EcmaHandleScope handleScope(thread);
117     JSHandle<JSTaggedValue> self = GetThis(argv);
118 
119     if (!self->IsJSAPILightWeightMap()) {
120         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
121             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
122         } else {
123             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
124                                                                 "The hasKey method cannot be bound");
125             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
126         }
127     }
128     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
129 
130     return JSAPILightWeightMap::HasKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
131 }
132 
HasValue(EcmaRuntimeCallInfo * argv)133 JSTaggedValue ContainersLightWeightMap::HasValue(EcmaRuntimeCallInfo *argv)
134 {
135     ASSERT(argv != nullptr);
136     JSThread *thread = argv->GetThread();
137     BUILTINS_API_TRACE(thread, LightWeightMap, HasValue);
138     [[maybe_unused]] EcmaHandleScope handleScope(thread);
139     JSHandle<JSTaggedValue> self = GetThis(argv);
140 
141     if (!self->IsJSAPILightWeightMap()) {
142         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
143             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
144         } else {
145             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
146                                                                 "The hasValue method cannot be bound");
147             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
148         }
149     }
150 
151     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
152     return JSAPILightWeightMap::HasValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value);
153 }
154 
IncreaseCapacityTo(EcmaRuntimeCallInfo * argv)155 JSTaggedValue ContainersLightWeightMap::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
156 {
157     ASSERT(argv != nullptr);
158     JSThread *thread = argv->GetThread();
159     BUILTINS_API_TRACE(thread, LightWeightMap, IncreaseCapacityTo);
160     [[maybe_unused]] EcmaHandleScope handleScope(thread);
161     JSHandle<JSTaggedValue> self = GetThis(argv);
162 
163     if (!self->IsJSAPILightWeightMap()) {
164         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
165             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
166         } else {
167             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
168                                                                 "The increaseCapacityTo method cannot be bound");
169             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
170         }
171     }
172 
173     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
174 
175     // for case like Math.foor(1.3), it gives double 1.0;
176     if (index->IsDouble()) {
177         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
178     }
179 
180     if (!index->IsInt()) {
181         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
182         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
183         CString errorMsg =
184             "The type of \"minimumCapacity\" must be small integer. Received value is: " + ConvertToString(*result);
185         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
186         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
187     }
188     JSAPILightWeightMap::IncreaseCapacityTo(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
189                                             index->GetInt());
190 
191     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
192     return JSTaggedValue::Undefined();
193 }
194 
Entries(EcmaRuntimeCallInfo * argv)195 JSTaggedValue ContainersLightWeightMap::Entries(EcmaRuntimeCallInfo *argv)
196 {
197     ASSERT(argv != nullptr);
198     JSThread *thread = argv->GetThread();
199     BUILTINS_API_TRACE(thread, LightWeightMap, Entries);
200     [[maybe_unused]] EcmaHandleScope handleScope(thread);
201     JSHandle<JSTaggedValue> self = GetThis(argv);
202     JSHandle<JSTaggedValue> iter =
203         JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
204     return iter.GetTaggedValue();
205 }
206 
Get(EcmaRuntimeCallInfo * argv)207 JSTaggedValue ContainersLightWeightMap::Get(EcmaRuntimeCallInfo *argv)
208 {
209     ASSERT(argv != nullptr);
210     JSThread *thread = argv->GetThread();
211     BUILTINS_API_TRACE(thread, LightWeightMap, Get);
212     [[maybe_unused]] EcmaHandleScope handleScope(thread);
213     JSHandle<JSTaggedValue> self = GetThis(argv);
214 
215     if (!self->IsJSAPILightWeightMap()) {
216         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
217             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
218         } else {
219             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
220                                                                 "The get method cannot be bound");
221             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
222         }
223     }
224 
225     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
226 
227     return JSAPILightWeightMap::Get(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
228 }
229 
GetIndexOfKey(EcmaRuntimeCallInfo * argv)230 JSTaggedValue ContainersLightWeightMap::GetIndexOfKey(EcmaRuntimeCallInfo *argv)
231 {
232     ASSERT(argv != nullptr);
233     JSThread *thread = argv->GetThread();
234     BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfKey);
235     [[maybe_unused]] EcmaHandleScope handleScope(thread);
236     JSHandle<JSTaggedValue> self = GetThis(argv);
237 
238     if (!self->IsJSAPILightWeightMap()) {
239         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
240             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
241         } else {
242             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
243                                                                 "The getIndexOfKey method cannot be bound");
244             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
245         }
246     }
247 
248     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
249 
250     int32_t index = JSAPILightWeightMap::GetIndexOfKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
251     return JSTaggedValue(index);
252 }
253 
GetIndexOfValue(EcmaRuntimeCallInfo * argv)254 JSTaggedValue ContainersLightWeightMap::GetIndexOfValue(EcmaRuntimeCallInfo *argv)
255 {
256     ASSERT(argv != nullptr);
257     JSThread *thread = argv->GetThread();
258     BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfValue);
259     [[maybe_unused]] EcmaHandleScope handleScope(thread);
260     JSHandle<JSTaggedValue> self = GetThis(argv);
261 
262     if (!self->IsJSAPILightWeightMap()) {
263         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
264             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
265         } else {
266             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
267                                                                 "The getIndexOfValue method cannot be bound");
268             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
269         }
270     }
271 
272     JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
273 
274     int32_t index = JSAPILightWeightMap::GetIndexOfValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value);
275     return JSTaggedValue(index);
276 }
277 
IsEmpty(EcmaRuntimeCallInfo * argv)278 JSTaggedValue ContainersLightWeightMap::IsEmpty(EcmaRuntimeCallInfo *argv)
279 {
280     ASSERT(argv != nullptr);
281     JSThread *thread = argv->GetThread();
282     BUILTINS_API_TRACE(thread, LightWeightMap, IsEmpty);
283     [[maybe_unused]] EcmaHandleScope handleScope(thread);
284     JSHandle<JSTaggedValue> self = GetThis(argv);
285 
286     if (!self->IsJSAPILightWeightMap()) {
287         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
288             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
289         } else {
290             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
291                                                                 "The isEmpty method cannot be bound");
292             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
293         }
294     }
295     return JSHandle<JSAPILightWeightMap>::Cast(self)->IsEmpty();
296 }
297 
GetKeyAt(EcmaRuntimeCallInfo * argv)298 JSTaggedValue ContainersLightWeightMap::GetKeyAt(EcmaRuntimeCallInfo *argv)
299 {
300     ASSERT(argv != nullptr);
301     JSThread *thread = argv->GetThread();
302     BUILTINS_API_TRACE(thread, LightWeightMap, GetKeyAt);
303     [[maybe_unused]] EcmaHandleScope handleScope(thread);
304     JSHandle<JSTaggedValue> self = GetThis(argv);
305 
306     if (!self->IsJSAPILightWeightMap()) {
307         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
308             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
309         } else {
310             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
311                                                                 "The getKeyAt method cannot be bound");
312             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
313         }
314     }
315 
316     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
317 
318     if (index->IsDouble()) {
319         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
320     }
321     if (!index->IsInt()) {
322         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
323         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
324         CString errorMsg =
325             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
326         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
327         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
328     }
329 
330     return JSAPILightWeightMap::GetKeyAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
331                                          index->GetInt());
332 }
333 
Keys(EcmaRuntimeCallInfo * argv)334 JSTaggedValue ContainersLightWeightMap::Keys(EcmaRuntimeCallInfo *argv)
335 {
336     ASSERT(argv != nullptr);
337     JSThread *thread = argv->GetThread();
338     BUILTINS_API_TRACE(thread, LightWeightMap, Keys);
339     [[maybe_unused]] EcmaHandleScope handleScope(thread);
340     JSHandle<JSTaggedValue> self = GetThis(argv);
341     JSHandle<JSTaggedValue> iter =
342         JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY);
343     return iter.GetTaggedValue();
344 }
345 
SetAll(EcmaRuntimeCallInfo * argv)346 JSTaggedValue ContainersLightWeightMap::SetAll(EcmaRuntimeCallInfo *argv)
347 {
348     ASSERT(argv != nullptr);
349     JSThread *thread = argv->GetThread();
350     BUILTINS_API_TRACE(thread, LightWeightMap, SetAll);
351     [[maybe_unused]] EcmaHandleScope handleScope(thread);
352     JSHandle<JSTaggedValue> self = GetThis(argv);
353 
354     if (!self->IsJSAPILightWeightMap()) {
355         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
356             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
357         } else {
358             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
359                                                                 "The setAll method cannot be bound");
360             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
361         }
362     }
363 
364     JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0));
365 
366     if (!lightWeightMap->IsJSAPILightWeightMap()) {
367         if (lightWeightMap->IsJSProxy() &&
368             JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) {
369             lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget());
370         } else {
371             JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue());
372             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
373             CString errorMsg =
374                 "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result);
375             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
376             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
377         }
378     }
379 
380     JSAPILightWeightMap::SetAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
381                                 JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap));
382     return JSTaggedValue::True();
383 }
384 
Set(EcmaRuntimeCallInfo * argv)385 JSTaggedValue ContainersLightWeightMap::Set(EcmaRuntimeCallInfo *argv)
386 {
387     ASSERT(argv != nullptr);
388     JSThread *thread = argv->GetThread();
389     BUILTINS_API_TRACE(thread, LightWeightMap, Set);
390     [[maybe_unused]] EcmaHandleScope handleScope(thread);
391     JSHandle<JSTaggedValue> self = GetThis(argv);
392 
393     if (!self->IsJSAPILightWeightMap()) {
394         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
395             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
396         } else {
397             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
398                                                                 "The set method cannot be bound");
399             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
400         }
401     }
402 
403     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
404     JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
405     JSHandle<JSAPILightWeightMap> lightWeightMap = JSHandle<JSAPILightWeightMap>::Cast(self);
406     JSAPILightWeightMap::Set(thread, lightWeightMap, key, value);
407 
408     return lightWeightMap.GetTaggedValue();
409 }
410 
Remove(EcmaRuntimeCallInfo * argv)411 JSTaggedValue ContainersLightWeightMap::Remove(EcmaRuntimeCallInfo *argv)
412 {
413     ASSERT(argv != nullptr);
414     JSThread *thread = argv->GetThread();
415     BUILTINS_API_TRACE(thread, LightWeightMap, Remove);
416     [[maybe_unused]] EcmaHandleScope handleScope(thread);
417     JSHandle<JSTaggedValue> self = GetThis(argv);
418 
419     if (!self->IsJSAPILightWeightMap()) {
420         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
421             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
422         } else {
423             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
424                                                                 "The remove method cannot be bound");
425             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
426         }
427     }
428     JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
429 
430     return JSAPILightWeightMap::Remove(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
431 }
432 
RemoveAt(EcmaRuntimeCallInfo * argv)433 JSTaggedValue ContainersLightWeightMap::RemoveAt(EcmaRuntimeCallInfo *argv)
434 {
435     ASSERT(argv != nullptr);
436     JSThread *thread = argv->GetThread();
437     BUILTINS_API_TRACE(thread, LightWeightMap, RemoveAt);
438     [[maybe_unused]] EcmaHandleScope handleScope(thread);
439     JSHandle<JSTaggedValue> self = GetThis(argv);
440 
441     if (!self->IsJSAPILightWeightMap()) {
442         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
443             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
444         } else {
445             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
446                                                                 "The removeAt method cannot be bound");
447             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
448         }
449     }
450 
451     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
452 
453     if (index->IsDouble()) {
454         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
455     }
456     if (!index->IsInt()) {
457         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
458         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
459         CString errorMsg =
460             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
461         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
462         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
463     }
464 
465     return JSAPILightWeightMap::RemoveAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
466                                          index->GetInt());
467 }
468 
Clear(EcmaRuntimeCallInfo * argv)469 JSTaggedValue ContainersLightWeightMap::Clear(EcmaRuntimeCallInfo *argv)
470 {
471     ASSERT(argv != nullptr);
472     JSThread *thread = argv->GetThread();
473     BUILTINS_API_TRACE(thread, LightWeightMap, Clear);
474     [[maybe_unused]] EcmaHandleScope handleScope(thread);
475     JSHandle<JSTaggedValue> self = GetThis(argv);
476 
477     if (!self->IsJSAPILightWeightMap()) {
478         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
479             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
480         } else {
481             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
482                                                                 "The clear method cannot be bound");
483             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
484         }
485     }
486 
487     JSAPILightWeightMap::Clear(thread, JSHandle<JSAPILightWeightMap>::Cast(self));
488     return JSTaggedValue::Undefined();
489 }
490 
SetValueAt(EcmaRuntimeCallInfo * argv)491 JSTaggedValue ContainersLightWeightMap::SetValueAt(EcmaRuntimeCallInfo *argv)
492 {
493     ASSERT(argv != nullptr);
494     JSThread *thread = argv->GetThread();
495     BUILTINS_API_TRACE(thread, LightWeightMap, SetValueAt);
496     [[maybe_unused]] EcmaHandleScope handleScope(thread);
497     JSHandle<JSTaggedValue> self = GetThis(argv);
498 
499     if (!self->IsJSAPILightWeightMap()) {
500         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
501             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
502         } else {
503             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
504                                                                 "The setValueAt method cannot be bound");
505             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
506         }
507     }
508 
509     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
510     JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
511     if (index->IsDouble()) {
512         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
513     }
514     if (!index->IsInt()) {
515         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
516         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
517         CString errorMsg =
518             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
519         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
520         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
521     }
522 
523     return JSAPILightWeightMap::SetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
524                                            index->GetInt(), value);
525 }
526 
ForEach(EcmaRuntimeCallInfo * argv)527 JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv)
528 {
529     ASSERT(argv != nullptr);
530     JSThread *thread = argv->GetThread();
531     BUILTINS_API_TRACE(thread, LightWeightMap, ForEach);
532     [[maybe_unused]] EcmaHandleScope handleScope(thread);
533     // get and check lightweightmap object
534     JSHandle<JSTaggedValue> self = GetThis(argv);
535     if (!self->IsJSAPILightWeightMap()) {
536         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
537             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
538         } else {
539             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
540                                                                 "The forEach method cannot be bound");
541             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
542         }
543     }
544     // get and check callback function
545     JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
546     if (!func->IsCallable()) {
547         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
548         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
549         CString errorMsg =
550             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
551         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
552         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
553     }
554     // If thisArg was supplied, let T be thisArg; else let T be undefined.
555     JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
556     JSHandle<JSAPILightWeightMap> tmap = JSHandle<JSAPILightWeightMap>::Cast(self);
557     JSMutableHandle<TaggedArray> keys(thread, tmap->GetKeys());
558     JSMutableHandle<TaggedArray> values(thread, tmap->GetValues());
559 
560     uint32_t index = 0;
561     uint32_t length = tmap->GetSize();
562     const uint32_t argsLength = 3;
563     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
564     while (index < length) {
565         // ignore the hash value is required to determine the true index
566         // Let funcResult be Call(callbackfn, T, «e, e, S»).
567         EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
568         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
569         info->SetCallArg(values->Get(index), keys->Get(index), self.GetTaggedValue());
570         JSTaggedValue ret = JSFunction::Call(info);
571         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
572 
573         // check entries should be update, size will be update in tmap set or remove.
574         if (tmap->GetSize() != length) {
575             keys.Update(tmap->GetKeys());
576             values.Update(tmap->GetValues());
577             length = tmap->GetSize();
578         }
579         index++;
580     }
581     return JSTaggedValue::Undefined();
582 }
583 
ToString(EcmaRuntimeCallInfo * argv)584 JSTaggedValue ContainersLightWeightMap::ToString(EcmaRuntimeCallInfo *argv)
585 {
586     ASSERT(argv != nullptr);
587     JSThread *thread = argv->GetThread();
588     BUILTINS_API_TRACE(thread, LightWeightMap, ToString);
589     [[maybe_unused]] EcmaHandleScope handleScope(thread);
590     JSHandle<JSTaggedValue> self = GetThis(argv);
591 
592     if (!self->IsJSAPILightWeightMap()) {
593         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
594             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
595         } else {
596             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
597                                                                 "The toString method cannot be bound");
598             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
599         }
600     }
601 
602     return JSAPILightWeightMap::ToString(thread, JSHandle<JSAPILightWeightMap>::Cast(self));
603 }
604 
GetValueAt(EcmaRuntimeCallInfo * argv)605 JSTaggedValue ContainersLightWeightMap::GetValueAt(EcmaRuntimeCallInfo *argv)
606 {
607     ASSERT(argv != nullptr);
608     JSThread *thread = argv->GetThread();
609     BUILTINS_API_TRACE(thread, LightWeightMap, GetValueAt);
610     [[maybe_unused]] EcmaHandleScope handleScope(thread);
611     JSHandle<JSTaggedValue> self = GetThis(argv);
612 
613     if (!self->IsJSAPILightWeightMap()) {
614         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
615             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
616         } else {
617             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
618                                                                 "The getValueAt method cannot be bound");
619             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
620         }
621     }
622     JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
623     if (index->IsDouble()) {
624         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
625     }
626     if (!index->IsInt()) {
627         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
628         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
629         CString errorMsg =
630             "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
631         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
632         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
633     }
634 
635     if (index->IsDouble()) {
636         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
637     }
638     return JSAPILightWeightMap::GetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
639                                            index->GetInt());
640 }
641 
Values(EcmaRuntimeCallInfo * argv)642 JSTaggedValue ContainersLightWeightMap::Values(EcmaRuntimeCallInfo *argv)
643 {
644     ASSERT(argv != nullptr);
645     JSThread *thread = argv->GetThread();
646     BUILTINS_API_TRACE(thread, LightWeightMap, Keys);
647     [[maybe_unused]] EcmaHandleScope handleScope(thread);
648     JSHandle<JSTaggedValue> self = GetThis(argv);
649     JSHandle<JSTaggedValue> iter =
650         JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::VALUE);
651     return iter.GetTaggedValue();
652 }
653 }  // namespace panda::ecmascript::containers
654