1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/js_tagged_value.h"
17
18 #include "ecmascript/ecma_macros.h"
19 #include "ecmascript/ecma_string-inl.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/interpreter/interpreter.h"
23 #include "ecmascript/js_api/js_api_arraylist.h"
24 #include "ecmascript/js_api/js_api_deque.h"
25 #include "ecmascript/js_api/js_api_lightweightset.h"
26 #include "ecmascript/js_api/js_api_lightweightmap.h"
27 #include "ecmascript/js_api/js_api_linked_list.h"
28 #include "ecmascript/js_api/js_api_list.h"
29 #include "ecmascript/js_api/js_api_plain_array.h"
30 #include "ecmascript/js_api/js_api_queue.h"
31 #include "ecmascript/js_api/js_api_stack.h"
32 #include "ecmascript/js_api/js_api_vector.h"
33 #include "ecmascript/js_array.h"
34 #include "ecmascript/js_date.h"
35 #include "ecmascript/js_handle.h"
36 #include "ecmascript/js_object-inl.h"
37 #include "ecmascript/js_primitive_ref.h"
38 #include "ecmascript/js_proxy.h"
39 #include "ecmascript/js_tagged_value-inl.h"
40 #include "ecmascript/js_thread.h"
41 #include "ecmascript/js_typed_array.h"
42 #include "ecmascript/message_string.h"
43 #include "ecmascript/module/js_module_namespace.h"
44 #include "ecmascript/tagged_array.h"
45 #include "ecmascript/object_factory.h"
46 #include "ecmascript/symbol_table.h"
47
48 namespace panda::ecmascript {
GetTypeString(JSThread * thread,PreferredPrimitiveType type)49 JSHandle<EcmaString> GetTypeString(JSThread *thread, PreferredPrimitiveType type)
50 {
51 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
52 if (type == NO_PREFERENCE) {
53 return JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
54 }
55 if (type == PREFER_NUMBER) {
56 return JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
57 }
58 return JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
59 }
60
ToPropertyKey(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)61 JSHandle<JSTaggedValue> JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
62 {
63 if (tagged->IsStringOrSymbol() || tagged->IsNumber()) {
64 return tagged;
65 }
66 JSHandle<JSTaggedValue> key(thread, ToPrimitive(thread, tagged, PREFER_STRING));
67 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
68 if (key->IsSymbol()) {
69 return key;
70 }
71 JSHandle<EcmaString> string = ToString(thread, key);
72 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
73 return JSHandle<JSTaggedValue>::Cast(string);
74 }
75
IsInteger() const76 bool JSTaggedValue::IsInteger() const
77 {
78 if (!IsNumber()) {
79 return false;
80 }
81
82 if (IsInt()) {
83 return true;
84 }
85
86 double thisValue = GetDouble();
87 // If argument is NaN, +∞, or -∞, return false.
88 if (!std::isfinite(thisValue)) {
89 return false;
90 }
91
92 // If floor(abs(argument)) ≠ abs(argument), return false.
93 if (std::floor(std::abs(thisValue)) != std::abs(thisValue)) {
94 return false;
95 }
96
97 return true;
98 }
99
IsJSCOWArray() const100 bool JSTaggedValue::IsJSCOWArray() const
101 {
102 // Elements of JSArray are shared and properties are not yet.
103 return IsJSArray() && JSArray::Cast(GetTaggedObject())->GetElements().IsCOWArray();
104 }
105
WithinInt32() const106 bool JSTaggedValue::WithinInt32() const
107 {
108 if (!IsNumber()) {
109 return false;
110 }
111
112 double doubleValue = GetNumber();
113 if (base::bit_cast<int64_t>(doubleValue) == base::bit_cast<int64_t>(-0.0)) {
114 return false;
115 }
116
117 int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
118 return doubleValue == static_cast<double>(intvalue);
119 }
120
IsZero() const121 bool JSTaggedValue::IsZero() const
122 {
123 if (GetRawData() == VALUE_ZERO) {
124 return true;
125 }
126 if (IsDouble()) {
127 const double limit = 1e-8;
128 return (std::abs(GetDouble() - 0.0) <= limit);
129 }
130 return false;
131 }
132
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)133 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
134 {
135 if (x->IsNumber()) {
136 if (y->IsNumber()) {
137 return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
138 }
139 if (y->IsString()) {
140 JSTaggedNumber yNumber = ToNumber(thread, y);
141 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
142 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
143 }
144 if (y->IsBoolean()) {
145 JSTaggedNumber yNumber = ToNumber(thread, y);
146 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
147 return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
148 }
149 if (y->IsBigInt()) {
150 return Equal(thread, y, x);
151 }
152 if (y->IsHeapObject() && !y->IsSymbol()) {
153 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
154 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
155 return Equal(thread, x, yPrimitive);
156 }
157 return false;
158 }
159
160 if (x->IsString()) {
161 if (y->IsString()) {
162 return EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(),
163 JSHandle<EcmaString>(x),
164 JSHandle<EcmaString>(y));
165 }
166 if (y->IsNumber()) {
167 JSTaggedNumber xNumber = ToNumber(thread, x);
168 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
169 return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
170 }
171 if (y->IsBoolean()) {
172 JSTaggedNumber xNumber = ToNumber(thread, x);
173 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
174 JSTaggedNumber yNumber = ToNumber(thread, y);
175 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
176 return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
177 }
178 if (y->IsBigInt()) {
179 return Equal(thread, y, x);
180 }
181 if (y->IsHeapObject() && !y->IsSymbol()) {
182 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
183 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
184 return Equal(thread, x, yPrimitive);
185 }
186 return false;
187 }
188
189 if (x->IsBoolean()) {
190 JSTaggedNumber xNumber = ToNumber(thread, x);
191 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
192 return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
193 }
194
195 if (x->IsSymbol()) {
196 if (y->IsSymbol()) {
197 return x.GetTaggedValue() == y.GetTaggedValue();
198 }
199 if (y->IsBigInt() || y->IsString()) {
200 return false;
201 }
202 if (y->IsHeapObject()) {
203 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
204 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
205 return Equal(thread, x, yPrimitive);
206 }
207 return false;
208 }
209
210 if (x->IsBigInt()) {
211 if (y->IsBigInt()) {
212 return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
213 }
214 if (y->IsString()) {
215 JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
216 if (!yNumber->IsBigInt()) {
217 return false;
218 }
219 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
220 }
221 if (y->IsBoolean()) {
222 JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
223 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
224 return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
225 }
226 if (y->IsNumber()) {
227 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
228 return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
229 }
230 if (y->IsHeapObject() && !y->IsSymbol()) {
231 JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
232 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
233 return Equal(thread, x, yPrimitive);
234 }
235 return false;
236 }
237
238 if (x->IsHeapObject()) {
239 if (y->IsHeapObject()) {
240 // if same type, must call Type::StrictEqual()
241 JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
242 JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
243 if (xType == yType) {
244 return StrictEqual(thread, x, y);
245 }
246 }
247 if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
248 JSHandle<JSTaggedValue> xPrimitive(thread, ToPrimitive(thread, x));
249 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
250 return Equal(thread, xPrimitive, y);
251 }
252 return false;
253 }
254
255 if (x->IsNull() && y->IsNull()) {
256 return true;
257 }
258
259 if (x->IsUndefined() && y->IsUndefined()) {
260 return true;
261 }
262
263 if (x->IsNull() && y->IsUndefined()) {
264 return true;
265 }
266
267 if (x->IsUndefined() && y->IsNull()) {
268 return true;
269 }
270
271 return false;
272 }
273
CountLeadingZeros(uint32_t value,uint32_t bits)274 uint32_t CountLeadingZeros(uint32_t value, uint32_t bits)
275 {
276 if (bits == 1) {
277 return value ^ 1;
278 }
279 uint32_t upper_half = value >> (bits / 2); // 2 : half
280 uint32_t nextValue = upper_half != 0 ? upper_half : value;
281 uint32_t add = upper_half != 0 ? 0 : (bits / 2); // 2 : half
282 uint32_t nextBits = bits == 1 ? 1 : bits / 2; // 2 : half
283 return CountLeadingZeros(nextValue, nextBits) + add;
284 }
285
286 const uint32_t kPowersOf10[] = {
287 1,
288 10,
289 100,
290 1000,
291 10 * 1000,
292 100 * 1000,
293 1000 * 1000,
294 10 * 1000 * 1000,
295 100 * 1000 * 1000,
296 1000 * 1000 * 1000,
297 };
298
IntLexicographicCompare(JSTaggedValue x,JSTaggedValue y)299 int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
300 {
301 ASSERT(x.IsInt() && y.IsInt());
302 int xValue = x.GetInt();
303 int yValue = y.GetInt();
304 if (xValue == yValue) {
305 return 0;
306 }
307 if (xValue == 0 || yValue == 0) {
308 return xValue > yValue ? 1 : -1;
309 }
310 uint32_t unsignedX = static_cast<uint32_t>(xValue);
311 uint32_t unsignedY = static_cast<uint32_t>(yValue);
312 if (yValue > 0) {
313 if (xValue < 0) {
314 return -1;
315 }
316 } else {
317 if (xValue > 0) {
318 return 1;
319 }
320 unsignedX = static_cast<uint32_t>(-xValue);
321 unsignedY = static_cast<uint32_t>(-yValue);
322 }
323 uint32_t bits = sizeof(uint32_t) * 8; // 8 : bits
324 int xLog2 = 31 - CountLeadingZeros(unsignedX, bits); // 31 : Algorithm implementation
325 int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
326 xDigit -= unsignedX < kPowersOf10[xDigit];
327
328 int yLog2 = 31 - CountLeadingZeros(unsignedY, bits); // 31 : Algorithm implementation
329 int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
330 yDigit -= unsignedY < kPowersOf10[yDigit];
331
332 int res = 0;
333 if (xDigit > yDigit) {
334 // X has fewer digits. We would like to simply scale up X but that
335 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
336 // be scaled up to 9_000_000_000. So we scale up by the next
337 // smallest power and scale down Y to drop one digit. It is OK to
338 // drop one digit from the longer integer since the final digit is
339 // past the length of the shorter integer.
340 unsignedY *= kPowersOf10[xDigit - yDigit - 1];
341 unsignedX /= 10; // 10 : Decimal
342 res = 1;
343 }
344 if (yDigit > xDigit) {
345 unsignedX *= kPowersOf10[yDigit - xDigit - 1];
346 unsignedY /= 10; // 10 : Decimal
347 res = -1;
348 }
349 if (unsignedX > unsignedY) {
350 return 1;
351 }
352
353 if (unsignedY > unsignedX) {
354 return -1;
355 }
356 return res;
357 }
358
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)359 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
360 const JSHandle<JSTaggedValue> &y)
361 {
362 if (x->IsDate() && y->IsDate()) {
363 double timeX = JSDate::Cast(x->GetTaggedObject())->GetTimeValue().GetDouble();
364 double timeY = JSDate::Cast(y->GetTaggedObject())->GetTimeValue().GetDouble();
365 return StrictNumberCompare(timeX, timeY);
366 }
367 JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
368 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
369 JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
370 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
371 if (primX->IsString() && primY->IsString()) {
372 auto xHandle = JSHandle<EcmaString>(primX);
373 auto yHandle = JSHandle<EcmaString>(primY);
374 int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
375 if (result < 0) {
376 return ComparisonResult::LESS;
377 }
378 if (result == 0) {
379 return ComparisonResult::EQUAL;
380 }
381 return ComparisonResult::GREAT;
382 }
383 if (primX->IsBigInt()) {
384 if (primY->IsNumber()) {
385 JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
386 return BigInt::CompareWithNumber(bigint, primY);
387 } else if (primY->IsString()) {
388 JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
389 if (!bigY->IsBigInt()) {
390 return ComparisonResult::UNDEFINED;
391 }
392 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
393 } else {
394 JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
395 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
396 return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
397 }
398 }
399 if (primY->IsBigInt()) {
400 ComparisonResult res = Compare(thread, primY, primX);
401 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
402 if (res == ComparisonResult::GREAT) {
403 return ComparisonResult::LESS;
404 } else if (res == ComparisonResult::LESS) {
405 return ComparisonResult::GREAT;
406 }
407 return res;
408 }
409 JSTaggedNumber xNumber = ToNumber(thread, x);
410 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
411 JSTaggedNumber yNumber = ToNumber(thread, y);
412 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
413 return StrictNumberCompare(xNumber.GetNumber(), yNumber.GetNumber());
414 }
415
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)416 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
417 {
418 if (x.IsNumber() && y.IsNumber()) {
419 return true;
420 }
421 if (x.IsBoolean() && y.IsBoolean()) {
422 return true;
423 }
424 if (x.IsString() && y.IsString()) {
425 return true;
426 }
427 if (x.IsHeapObject() && y.IsHeapObject()) {
428 return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
429 }
430
431 return false;
432 }
433
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)434 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
435 PreferredPrimitiveType type)
436 {
437 if (tagged->IsECMAObject()) {
438 EcmaVM *vm = thread->GetEcmaVM();
439 JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
440
441 JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
442 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
443 if (!exoticToprim->IsUndefined()) {
444 JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
445 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
446 EcmaRuntimeCallInfo *info =
447 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
448 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
449 info->SetCallArg(value);
450 JSTaggedValue valueResult = JSFunction::Call(info);
451 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
452 if (!valueResult.IsECMAObject()) {
453 return valueResult;
454 }
455 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert object to primitive value",
456 JSTaggedValue::Exception());
457 } else {
458 type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
459 return OrdinaryToPrimitive(thread, tagged, type);
460 }
461 }
462 return tagged.GetTaggedValue();
463 }
464
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)465 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
466 PreferredPrimitiveType type)
467 {
468 static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
469 ASSERT(tagged->IsECMAObject());
470 auto globalConst = thread->GlobalConstants();
471 for (uint8_t i = 0; i < 2; i++) { // 2: 2 means value has 2 target types, string or value.
472 JSHandle<JSTaggedValue> keyString;
473 if ((static_cast<uint8_t>(type) ^ i) != 0) {
474 keyString = globalConst->GetHandledToStringString();
475 } else {
476 keyString = globalConst->GetHandledValueOfString();
477 }
478 JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
479 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
480 if (entryfunc->IsCallable()) {
481 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
482 EcmaRuntimeCallInfo *info =
483 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
484 JSTaggedValue valueResult = JSFunction::Call(info);
485 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
486 if (!valueResult.IsECMAObject()) {
487 return valueResult;
488 }
489 }
490 }
491 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
492 }
493
ToString(JSThread * thread,JSTaggedValue val)494 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
495 {
496 JSHandle<JSTaggedValue> tagged(thread, val);
497 return ToString(thread, tagged);
498 }
499
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)500 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
501 {
502 if (tagged->IsString()) {
503 return JSHandle<EcmaString>(tagged);
504 }
505 auto globalConst = thread->GlobalConstants();
506 if (tagged->IsSpecial()) {
507 switch (tagged->GetRawData()) {
508 case VALUE_UNDEFINED: {
509 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
510 }
511 case VALUE_NULL: {
512 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
513 }
514 case VALUE_TRUE: {
515 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
516 }
517 case VALUE_FALSE: {
518 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
519 }
520 case VALUE_HOLE: {
521 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
522 }
523 default:
524 break;
525 }
526 }
527
528 if (tagged->IsNumber()) {
529 return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
530 }
531
532 if (tagged->IsBigInt()) {
533 JSHandle<BigInt> taggedValue(tagged);
534 return BigInt::ToString(thread, taggedValue);
535 }
536
537 if (tagged->IsNativePointer()) {
538 return NativePointerToString(thread, tagged);
539 }
540
541 auto emptyStr = globalConst->GetHandledEmptyString();
542 if (tagged->IsECMAObject()) {
543 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
544 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
545 return ToString(thread, primValue);
546 }
547 // Already Include Symbol
548 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
549 }
550
NativePointerToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)551 JSHandle<EcmaString> JSTaggedValue::NativePointerToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
552 {
553 JSHandle<JSNativePointer> taggedHandle(tagged);
554 std::stringstream stringstream;
555 stringstream << std::hex << taggedHandle->GetExternalPointer();
556 std::string nativePtrStr = "[External: " + stringstream.str() + "]";
557
558 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
559 return factory->NewFromASCII(nativePtrStr);
560 }
561
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)562 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
563 {
564 if (tagged->IsNumber()) {
565 return tagged.GetTaggedValue();
566 }
567
568 if (tagged->IsString()) {
569 JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
570 if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), JSHandle<EcmaString>(tagged), str)) {
571 return JSTaggedValue(-0.0);
572 }
573 JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
574 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
575 if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
576 return tmp.GetTaggedValue();
577 }
578 }
579 return JSTaggedValue::Undefined();
580 }
581
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)582 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
583 {
584 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
585 if (tagged->IsInt() || tagged->IsDouble()) {
586 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
587 }
588
589 switch (tagged->GetRawData()) {
590 case JSTaggedValue::VALUE_UNDEFINED: {
591 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
592 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
593 }
594 case JSTaggedValue::VALUE_HOLE: {
595 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
596 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
597 }
598 case JSTaggedValue::VALUE_NULL: {
599 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
600 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
601 }
602 case JSTaggedValue::VALUE_TRUE:
603 case JSTaggedValue::VALUE_FALSE: {
604 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
605 }
606 default: {
607 break;
608 }
609 }
610
611 if (tagged->IsECMAObject()) {
612 return JSHandle<JSObject>::Cast(tagged);
613 }
614 if (tagged->IsSymbol()) {
615 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
616 }
617 if (tagged->IsString()) {
618 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
619 }
620 if (tagged->IsBigInt()) {
621 return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
622 }
623 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
624 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
625 }
626
627 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)628 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
629 const JSHandle<JSTaggedValue> &key)
630 {
631 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
632 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
633 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
634 std::string message = "Cannot read property ";
635 message.append(keyStr).append(" of ").append(objStr);
636 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
637 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
638 }
639 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
640
641 if (obj->IsJSProxy()) {
642 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
643 }
644 if (obj->IsTypedArray()) {
645 return JSTypedArray::GetProperty(thread, obj, key);
646 }
647 if (obj->IsModuleNamespace()) {
648 return ModuleNamespace::GetProperty(thread, obj, key);
649 }
650
651 if (obj->IsSpecialContainer()) {
652 return GetJSAPIProperty(thread, obj, key);
653 }
654
655 return JSObject::GetProperty(thread, obj, key);
656 }
657
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)658 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
659 {
660 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
661 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
662 std::string message = "Cannot read property ";
663 message.append(ToCString(key)).append(" of ").append(objStr);
664 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
665 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
666 }
667
668 if (obj->IsJSProxy()) {
669 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
670 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
671 }
672
673 if (obj->IsTypedArray()) {
674 return JSTypedArray::GetProperty(thread, obj, key);
675 }
676
677 if (obj->IsSpecialContainer()) {
678 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
679 return GetJSAPIProperty(thread, obj, keyHandle);
680 }
681
682 return JSObject::GetProperty(thread, obj, key);
683 }
684
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)685 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
686 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
687 {
688 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
689 std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
690 std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
691 std::string message = "Cannot read property ";
692 message.append(keyStr).append(" of ").append(objStr);
693 THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
694 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
695 }
696 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
697
698 if (obj->IsJSProxy()) {
699 return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
700 }
701 if (obj->IsTypedArray()) {
702 return JSTypedArray::GetProperty(thread, obj, key, receiver);
703 }
704
705 if (obj->IsSpecialContainer()) {
706 return GetJSAPIProperty(thread, obj, key);
707 }
708
709 return JSObject::GetProperty(thread, obj, key, receiver);
710 }
711
712 // 7.3.3 Set (O, P, V, Throw)
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,bool mayThrow)713 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
714 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow)
715 {
716 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
717 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
718 }
719
720 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
721
722 // 4. Let success be O.[[Set]](P, V, O).
723 bool success = false;
724 if (obj->IsJSProxy()) {
725 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
726 } else if (obj->IsTypedArray()) {
727 success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
728 } else if (obj->IsModuleNamespace()) {
729 success = ModuleNamespace::SetProperty(thread, mayThrow);
730 } else if (obj->IsSpecialContainer()) {
731 success = SetJSAPIProperty(thread, obj, key, value);
732 } else {
733 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
734 }
735 // 5. ReturnIfAbrupt(success).
736 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
737 // 6. If success is false and Throw is true, throw a TypeError exception.
738 // have done in JSObject::SetPropert.
739 return success;
740 }
741
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)742 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
743 const JSHandle<JSTaggedValue> &value, bool mayThrow)
744 {
745 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
746 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
747 }
748
749 // 4. Let success be O.[[Set]](P, V, O).
750 bool success = false;
751 if (obj->IsJSProxy()) {
752 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
753 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
754 } else if (obj->IsTypedArray()) {
755 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
756 success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
757 } else if (obj->IsModuleNamespace()) {
758 success = ModuleNamespace::SetProperty(thread, mayThrow);
759 } else if (obj->IsSpecialContainer()) {
760 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
761 success = SetJSAPIProperty(thread, obj, keyHandle, value);
762 } else {
763 success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
764 }
765 // 5. ReturnIfAbrupt(success).
766 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
767 // 6. If success is false and Throw is true, throw a TypeError exception.
768 // have done in JSObject::SetPropert.
769 return success;
770 }
771
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)772 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
773 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
774 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
775 {
776 if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
777 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
778 }
779
780 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
781
782 // 4. Let success be O.[[Set]](P, V, O).
783 bool success = false;
784 if (obj->IsJSProxy()) {
785 success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
786 } else if (obj->IsTypedArray()) {
787 success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
788 } else if (obj->IsModuleNamespace()) {
789 success = ModuleNamespace::SetProperty(thread, mayThrow);
790 } else if (obj->IsSpecialContainer()) {
791 success = SetJSAPIProperty(thread, obj, key, value);
792 } else {
793 success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
794 }
795 // 5. ReturnIfAbrupt(success).
796 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
797 // 6. If success is false and Throw is true, throw a TypeError exception.
798 // have done in JSObject::SetPropert.
799 return success;
800 }
801
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)802 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
803 const JSHandle<JSTaggedValue> &key)
804 {
805 if (obj->IsJSProxy()) {
806 return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
807 }
808
809 if (obj->IsModuleNamespace()) {
810 return ModuleNamespace::DeleteProperty(thread, obj, key);
811 }
812
813 if (obj->IsTypedArray()) {
814 return JSTypedArray::DeleteProperty(thread, obj, key);
815 }
816
817 if (obj->IsSpecialContainer()) {
818 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
819 }
820
821 return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
822 }
823
824 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)825 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
826 const JSHandle<JSTaggedValue> &key)
827 {
828 if (!obj->IsECMAObject()) {
829 THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
830 }
831 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
832
833 // 3. Let success be O.[[Delete]](P).
834 bool success = DeleteProperty(thread, obj, key);
835
836 // 4. ReturnIfAbrupt(success).
837 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
838 // 5. If success is false, throw a TypeError exception
839 if (!success) {
840 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
841 }
842 return success;
843 }
844
845 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)846 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
847 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
848 {
849 // 1. Assert: Type(O) is Object.
850 // 2. Assert: IsPropertyKey(P) is true.
851 ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
852 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
853 // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
854 bool success = DefineOwnProperty(thread, obj, key, desc);
855 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
856 // 4. If success is false, throw a TypeError exception.
857 if (!success) {
858 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot define property", false);
859 }
860 return success;
861 }
862
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)863 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
864 const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
865 {
866 if (obj->IsJSArray()) {
867 return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
868 }
869
870 if (obj->IsJSProxy()) {
871 return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
872 }
873
874 if (obj->IsTypedArray()) {
875 return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
876 }
877
878 if (obj->IsModuleNamespace()) {
879 return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
880 }
881
882 if (obj->IsSpecialContainer()) {
883 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
884 }
885
886 return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
887 }
888
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)889 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
890 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
891 {
892 if (obj->IsJSProxy()) {
893 return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
894 }
895 if (obj->IsTypedArray()) {
896 return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
897 }
898 if (obj->IsModuleNamespace()) {
899 return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
900 }
901 if (obj->IsSpecialContainer()) {
902 return GetContainerProperty(thread, obj, key, desc);
903 }
904 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
905 }
906
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto)907 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
908 const JSHandle<JSTaggedValue> &proto)
909 {
910 if (obj->IsJSShared() || proto->IsJSShared()) {
911 THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetProtoWithSendable), false);
912 }
913
914 if (obj->IsJSProxy()) {
915 return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
916 }
917 if (obj->IsModuleNamespace()) {
918 return ModuleNamespace::SetPrototype(obj, proto);
919 }
920 if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
921 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
922 }
923 if (obj->IsJSFunction() && proto->IsJSFunction()) {
924 JSHandle<JSFunction> objFunc = JSHandle<JSFunction>::Cast(obj);
925 JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
926 if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor()) {
927 JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
928 objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
929 }
930 }
931
932 return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto);
933 }
934
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)935 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
936 {
937 if (!obj->IsECMAObject()) {
938 LOG_ECMA(INFO) << "[ECMAObject?] " << obj->GetRawData();
939 std::ostringstream oss;
940 obj.GetTaggedValue().Dump(oss);
941 LOG_ECMA(INFO) << "[ECMAObject?] " << oss.str();
942 THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
943 }
944 if (obj->IsJSProxy()) {
945 return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
946 }
947 return JSObject::GetPrototype(JSHandle<JSObject>(obj));
948 }
949
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)950 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
951 {
952 if (obj->IsJSProxy()) {
953 return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
954 }
955 if (obj->IsModuleNamespace()) {
956 return ModuleNamespace::PreventExtensions();
957 }
958 return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
959 }
960
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)961 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
962 {
963 if (obj->IsJSProxy()) {
964 return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
965 }
966 if (obj->IsTypedArray()) {
967 return JSTypedArray::OwnPropertyKeys(thread, obj);
968 }
969 if (obj->IsSpecialContainer()) {
970 return GetOwnContainerPropertyKeys(thread, obj);
971 }
972 if (obj->IsModuleNamespace()) {
973 return ModuleNamespace::OwnPropertyKeys(thread, obj);
974 }
975 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
976 }
977
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)978 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
979 const JSHandle<JSTaggedValue> &obj, uint32_t filter)
980 {
981 if (obj->IsJSProxy()) {
982 return JSProxy::GetAllPropertyKeys(thread, JSHandle<JSProxy>(obj), filter);
983 }
984 if (obj->IsTypedArray()) {
985 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
986 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
987 }
988 if (obj->IsSpecialContainer()) {
989 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
990 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
991 }
992 if (obj->IsModuleNamespace()) {
993 LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
994 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
995 }
996 return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
997 }
998
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)999 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1000 {
1001 ASSERT(!obj->IsJSProxy());
1002 if (obj->IsTypedArray()) {
1003 return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
1004 }
1005 if (obj->IsSpecialContainer()) {
1006 return GetOwnContainerEnumPropertyKeys(thread, obj);
1007 }
1008 if (obj->IsModuleNamespace()) {
1009 return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
1010 }
1011 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1012 }
1013
1014 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1015 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1016 const JSHandle<JSTaggedValue> &key)
1017 {
1018 if (obj->IsJSProxy()) {
1019 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
1020 }
1021 if (obj->IsTypedArray()) {
1022 return JSTypedArray::HasProperty(thread, obj, key);
1023 }
1024 if (obj->IsModuleNamespace()) {
1025 return ModuleNamespace::HasProperty(thread, obj, key);
1026 }
1027 if (obj->IsSpecialContainer()) {
1028 return HasContainerProperty(thread, obj, key);
1029 }
1030 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1031 }
1032
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1033 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1034 {
1035 if (obj->IsJSProxy()) {
1036 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1037 return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1038 }
1039 if (obj->IsTypedArray()) {
1040 JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1041 return JSTypedArray::HasProperty(thread, obj, keyHandle);
1042 }
1043 if (obj->IsSpecialContainer()) {
1044 return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
1045 }
1046 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1047 }
1048
1049 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1050 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1051 const JSHandle<JSTaggedValue> &key)
1052 {
1053 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1054
1055 PropertyDescriptor desc(thread);
1056 return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
1057 }
1058
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)1059 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1060 {
1061 ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1062
1063 PropertyDescriptor desc(thread);
1064 return JSObject::GlobalGetOwnProperty(thread, key, desc);
1065 }
1066
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1067 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1068 {
1069 // 1. If v is an Object, return true.
1070 if (tagged->IsECMAObject()) {
1071 return true;
1072 }
1073 // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
1074 if (tagged->IsSymbol()) {
1075 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1076 auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
1077 JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
1078 if (key.IsUndefined()) {
1079 return true;
1080 }
1081 }
1082 // 3. Return false.
1083 return false;
1084 }
1085
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1086 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1087 {
1088 if (tagged->IsInt() && tagged->GetInt() >= 0) {
1089 return JSTaggedNumber(tagged.GetTaggedValue());
1090 }
1091 if (tagged->IsUndefined()) {
1092 return JSTaggedNumber(0);
1093 }
1094 JSTaggedNumber integerIndex = ToNumber(thread, tagged);
1095 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
1096 if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
1097 return integerIndex;
1098 }
1099 double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
1100 if (len < 0.0 || len > SAFE_NUMBER) {
1101 THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
1102 JSTaggedNumber::Exception());
1103 }
1104 return JSTaggedNumber(len);
1105 }
1106
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1107 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1108 {
1109 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1110
1111 if (obj->IsNumber()) {
1112 return JSHandle<JSTaggedValue>(thread,
1113 env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1114 }
1115 if (obj->IsBoolean()) {
1116 return JSHandle<JSTaggedValue>(thread,
1117 env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1118 }
1119 if (obj->IsString()) {
1120 return JSHandle<JSTaggedValue>(thread,
1121 env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1122 }
1123 if (obj->IsSymbol()) {
1124 return JSHandle<JSTaggedValue>(thread,
1125 env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1126 }
1127 if (obj->IsBigInt()) {
1128 return JSHandle<JSTaggedValue>(thread,
1129 env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1130 }
1131 return obj;
1132 }
1133
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1134 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1135 {
1136 if (obj->IsUndefined()) {
1137 return JSTaggedValue::Undefined();
1138 }
1139
1140 ASSERT(obj->IsECMAObject());
1141 return JSTaggedValue::GetPrototype(thread, obj);
1142 }
1143
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1144 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1145 const JSHandle<JSTaggedValue> &key)
1146 {
1147 auto *hclass = obj->GetTaggedObject()->GetClass();
1148 JSType jsType = hclass->GetObjectType();
1149 switch (jsType) {
1150 case JSType::JS_API_ARRAY_LIST: {
1151 return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1152 }
1153 case JSType::JS_API_QUEUE: {
1154 return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1155 }
1156 case JSType::JS_API_PLAIN_ARRAY: {
1157 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1158 }
1159 case JSType::JS_API_DEQUE: {
1160 return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1161 }
1162 case JSType::JS_API_STACK: {
1163 return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1164 }
1165 case JSType::JS_API_LIST: {
1166 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1167 return list->Has(key.GetTaggedValue());
1168 }
1169 case JSType::JS_API_LINKED_LIST: {
1170 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1171 return linkedList->Has(key.GetTaggedValue());
1172 }
1173 case JSType::JS_API_HASH_MAP:
1174 case JSType::JS_API_HASH_SET:
1175 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1176 case JSType::JS_API_LIGHT_WEIGHT_SET:
1177 case JSType::JS_API_TREE_MAP:
1178 case JSType::JS_API_TREE_SET: {
1179 return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1180 }
1181 case JSType::JS_API_VECTOR: {
1182 return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1183 }
1184 default: {
1185 LOG_ECMA(FATAL) << "this branch is unreachable";
1186 UNREACHABLE();
1187 }
1188 }
1189 return false;
1190 }
1191
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1192 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1193 {
1194 auto *hclass = obj->GetTaggedObject()->GetClass();
1195 JSType jsType = hclass->GetObjectType();
1196 switch (jsType) {
1197 case JSType::JS_API_ARRAY_LIST: {
1198 return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1199 }
1200 case JSType::JS_API_QUEUE: {
1201 return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1202 }
1203 case JSType::JS_API_PLAIN_ARRAY: {
1204 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1205 }
1206 case JSType::JS_API_DEQUE: {
1207 return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1208 }
1209 case JSType::JS_API_STACK: {
1210 return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1211 }
1212 case JSType::JS_API_LIST: {
1213 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1214 }
1215 case JSType::JS_API_LINKED_LIST: {
1216 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1217 }
1218 case JSType::JS_API_HASH_MAP:
1219 case JSType::JS_API_HASH_SET:
1220 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1221 case JSType::JS_API_LIGHT_WEIGHT_SET:
1222 case JSType::JS_API_TREE_MAP:
1223 case JSType::JS_API_TREE_SET: {
1224 return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1225 }
1226 case JSType::JS_API_VECTOR: {
1227 return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1228 }
1229 default: {
1230 LOG_ECMA(FATAL) << "this branch is unreachable";
1231 UNREACHABLE();
1232 }
1233 }
1234 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1235 }
1236
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1237 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1238 const JSHandle<JSTaggedValue> &obj)
1239 {
1240 auto *hclass = obj->GetTaggedObject()->GetClass();
1241 JSType jsType = hclass->GetObjectType();
1242 switch (jsType) {
1243 case JSType::JS_API_QUEUE: {
1244 return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1245 }
1246 case JSType::JS_API_DEQUE: {
1247 return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1248 }
1249 case JSType::JS_API_LIST: {
1250 return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1251 }
1252 case JSType::JS_API_LINKED_LIST: {
1253 return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1254 }
1255 case JSType::JS_API_VECTOR:
1256 case JSType::JS_API_STACK:
1257 case JSType::JS_API_ARRAY_LIST:
1258 case JSType::JS_API_PLAIN_ARRAY:
1259 case JSType::JS_API_HASH_MAP:
1260 case JSType::JS_API_HASH_SET:
1261 case JSType::JS_API_LIGHT_WEIGHT_MAP:
1262 case JSType::JS_API_LIGHT_WEIGHT_SET:
1263 case JSType::JS_API_TREE_MAP:
1264 case JSType::JS_API_TREE_SET: {
1265 return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1266 }
1267 default: {
1268 UNREACHABLE();
1269 }
1270 }
1271 return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1272 }
1273
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1274 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1275 const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1276 {
1277 if (key->IsInteger()) {
1278 auto *hclass = obj->GetTaggedObject()->GetClass();
1279 JSType jsType = hclass->GetObjectType();
1280 switch (jsType) {
1281 case JSType::JS_API_ARRAY_LIST: {
1282 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1283 }
1284 case JSType::JS_API_QUEUE: {
1285 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1286 }
1287 case JSType::JS_API_DEQUE: {
1288 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1289 }
1290 case JSType::JS_API_STACK: {
1291 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1292 }
1293 case JSType::JS_API_LIST: {
1294 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1295 }
1296 case JSType::JS_API_LINKED_LIST: {
1297 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1298 }
1299 case JSType::JS_API_PLAIN_ARRAY: {
1300 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1301 }
1302 case JSType::JS_API_VECTOR: {
1303 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1304 }
1305 default: {
1306 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1307 }
1308 }
1309 } else {
1310 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1311 }
1312 return false;
1313 }
1314
StringToNumber(JSTaggedValue tagged)1315 JSTaggedNumber JSTaggedValue::StringToNumber(JSTaggedValue tagged)
1316 {
1317 EcmaStringAccessor strAccessor(tagged);
1318 size_t strLen = strAccessor.GetLength();
1319 if (strLen == 0) {
1320 return JSTaggedNumber(0);
1321 }
1322 if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
1323 uint32_t index;
1324 // fast path: get integer from string's hash value
1325 if (strAccessor.TryToGetInteger(&index)) {
1326 return JSTaggedNumber(index);
1327 }
1328 Span<const uint8_t> str = strAccessor.FastToUtf8Span();
1329 if (strAccessor.GetLength() == 0) {
1330 return JSTaggedNumber(0);
1331 }
1332 auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged);
1333 if (isSuccess) {
1334 return result;
1335 }
1336 }
1337 CVector<uint8_t> buf;
1338 Span<const uint8_t> str = strAccessor.ToUtf8Span(buf);
1339 double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
1340 base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
1341 return JSTaggedNumber(d);
1342 }
1343
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1344 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1345 {
1346 // 1. Let primValue be ? ToPrimitive(value, number)
1347 JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
1348 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1349 // 2. If Type(primValue) is BigInt, return primValue.
1350 if (primValue.IsBigInt()) {
1351 return JSHandle<JSTaggedValue>(thread, primValue);
1352 }
1353 // 3. Return ? ToNumber(primValue).
1354 JSTaggedNumber number = ToNumber(thread, primValue);
1355 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1356 JSHandle<JSTaggedValue> value(thread, number);
1357 return value;
1358 }
1359
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1360 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1361 const JSHandle<JSTaggedValue> &key)
1362 {
1363 if (key->IsInteger()) {
1364 auto *hclass = obj->GetTaggedObject()->GetClass();
1365 JSType jsType = hclass->GetObjectType();
1366 switch (jsType) {
1367 case JSType::JS_API_ARRAY_LIST: {
1368 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1369 }
1370 case JSType::JS_API_LIST: {
1371 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1372 }
1373 case JSType::JS_API_LINKED_LIST: {
1374 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1375 }
1376 case JSType::JS_API_QUEUE: {
1377 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1378 }
1379 case JSType::JS_API_DEQUE: {
1380 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1381 }
1382 case JSType::JS_API_STACK: {
1383 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1384 }
1385 case JSType::JS_API_PLAIN_ARRAY: {
1386 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1387 }
1388 case JSType::JS_API_VECTOR: {
1389 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1390 }
1391 default: {
1392 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1393 }
1394 }
1395 } else {
1396 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1397 }
1398 return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1399 }
1400
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1401 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1402 const JSHandle<JSTaggedValue> &key,
1403 const JSHandle<JSTaggedValue> &value)
1404 {
1405 if (key->IsInteger()) {
1406 auto *hclass = obj->GetTaggedObject()->GetClass();
1407 JSType jsType = hclass->GetObjectType();
1408 switch (jsType) {
1409 case JSType::JS_API_ARRAY_LIST: {
1410 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1411 }
1412 case JSType::JS_API_LIST: {
1413 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1414 }
1415 case JSType::JS_API_LINKED_LIST: {
1416 return JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1417 }
1418 case JSType::JS_API_QUEUE: {
1419 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1420 }
1421 case JSType::JS_API_DEQUE: {
1422 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1423 }
1424 case JSType::JS_API_STACK: {
1425 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1426 }
1427 case JSType::JS_API_PLAIN_ARRAY: {
1428 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1429 }
1430 case JSType::JS_API_VECTOR: {
1431 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1432 }
1433 default: {
1434 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1435 }
1436 }
1437 } else {
1438 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1439 }
1440 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1441 }
1442 } // namespace panda::ecmascript
1443