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