• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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