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