• 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_vm.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/interpreter/interpreter.h"
22 #include "ecmascript/js_api/js_api_arraylist.h"
23 #include "ecmascript/js_api/js_api_deque.h"
24 #include "ecmascript/js_api/js_api_lightweightset.h"
25 #include "ecmascript/js_api/js_api_lightweightmap.h"
26 #include "ecmascript/js_api/js_api_linked_list.h"
27 #include "ecmascript/js_api/js_api_list.h"
28 #include "ecmascript/js_api/js_api_plain_array.h"
29 #include "ecmascript/js_api/js_api_queue.h"
30 #include "ecmascript/js_api/js_api_stack.h"
31 #include "ecmascript/js_api/js_api_vector.h"
32 #include "ecmascript/js_array.h"
33 #include "ecmascript/js_handle.h"
34 #include "ecmascript/js_object-inl.h"
35 #include "ecmascript/js_primitive_ref.h"
36 #include "ecmascript/js_proxy.h"
37 #include "ecmascript/js_tagged_value-inl.h"
38 #include "ecmascript/js_thread.h"
39 #include "ecmascript/js_typed_array.h"
40 #include "ecmascript/module/js_module_namespace.h"
41 #include "ecmascript/tagged_array.h"
42 #include "ecmascript/object_factory.h"
43 
44 namespace panda::ecmascript {
GetTypeString(JSThread * thread,PreferredPrimitiveType type)45 JSHandle<EcmaString> GetTypeString(JSThread *thread, PreferredPrimitiveType type)
46 {
47     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
48     if (type == NO_PREFERENCE) {
49         return JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
50     }
51     if (type == PREFER_NUMBER) {
52         return JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
53     }
54     return JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
55 }
56 
ToPropertyKey(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)57 JSHandle<JSTaggedValue> JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
58 {
59     if (tagged->IsStringOrSymbol() || tagged->IsNumber()) {
60         return tagged;
61     }
62     JSHandle<JSTaggedValue> key(thread, ToPrimitive(thread, tagged, PREFER_STRING));
63     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
64     if (key->IsSymbol()) {
65         return key;
66     }
67     JSHandle<EcmaString> string = ToString(thread, key);
68     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
69     return JSHandle<JSTaggedValue>::Cast(string);
70 }
71 
IsInteger() const72 bool JSTaggedValue::IsInteger() const
73 {
74     if (!IsNumber()) {
75         return false;
76     }
77 
78     if (IsInt()) {
79         return true;
80     }
81 
82     double thisValue = GetDouble();
83     // If argument is NaN, +∞, or -∞, return false.
84     if (!std::isfinite(thisValue)) {
85         return false;
86     }
87 
88     // If floor(abs(argument)) ≠ abs(argument), return false.
89     if (std::floor(std::abs(thisValue)) != std::abs(thisValue)) {
90         return false;
91     }
92 
93     return true;
94 }
95 
IsJSCOWArray() const96 bool JSTaggedValue::IsJSCOWArray() const
97 {
98     // Elements of JSArray are shared and properties are not yet.
99     return IsJSArray() && JSArray::Cast(GetTaggedObject())->GetElements().IsCOWArray();
100 }
101 
WithinInt32() const102 bool JSTaggedValue::WithinInt32() const
103 {
104     if (!IsNumber()) {
105         return false;
106     }
107 
108     double doubleValue = GetNumber();
109     if (bit_cast<int64_t>(doubleValue) == bit_cast<int64_t>(-0.0)) {
110         return false;
111     }
112 
113     int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
114     return doubleValue == static_cast<double>(intvalue);
115 }
116 
IsZero() const117 bool JSTaggedValue::IsZero() const
118 {
119     if (GetRawData() == VALUE_ZERO) {
120         return true;
121     }
122     if (IsDouble()) {
123         const double limit = 1e-8;
124         return (std::abs(GetDouble() - 0.0) <= limit);
125     }
126     return false;
127 }
128 
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)129 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
130 {
131     if (x->IsNumber()) {
132         if (y->IsNumber()) {
133             return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
134         }
135         if (y->IsString()) {
136             JSTaggedNumber yNumber = ToNumber(thread, y);
137             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
138             return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
139         }
140         if (y->IsBoolean()) {
141             JSTaggedNumber yNumber = ToNumber(thread, y);
142             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
143             return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
144         }
145         if (y->IsBigInt()) {
146             return Equal(thread, y, x);
147         }
148         if (y->IsHeapObject() && !y->IsSymbol()) {
149             JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
150             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
151             return Equal(thread, x, yPrimitive);
152         }
153         return false;
154     }
155 
156     if (x->IsString()) {
157         if (y->IsString()) {
158             return EcmaStringAccessor::StringsAreEqual(static_cast<EcmaString *>(x->GetTaggedObject()),
159                                                        static_cast<EcmaString *>(y->GetTaggedObject()));
160         }
161         if (y->IsNumber()) {
162             JSTaggedNumber xNumber = ToNumber(thread, x);
163             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
164             return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
165         }
166         if (y->IsBoolean()) {
167             JSTaggedNumber xNumber = ToNumber(thread, x);
168             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
169             JSTaggedNumber yNumber = ToNumber(thread, y);
170             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
171             return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
172         }
173         if (y->IsBigInt()) {
174             return Equal(thread, y, x);
175         }
176         if (y->IsHeapObject() && !y->IsSymbol()) {
177             JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
178             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
179             return Equal(thread, x, yPrimitive);
180         }
181         return false;
182     }
183 
184     if (x->IsBoolean()) {
185         JSTaggedNumber xNumber = ToNumber(thread, x);
186         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
187         return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
188     }
189 
190     if (x->IsSymbol()) {
191         if (y->IsSymbol()) {
192             return x.GetTaggedValue() == y.GetTaggedValue();
193         }
194         if (y->IsBigInt()) {
195             return Equal(thread, y, x);
196         }
197         if (y->IsHeapObject()) {
198             JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
199             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
200             return Equal(thread, x, yPrimitive);
201         }
202         return false;
203     }
204 
205     if (x->IsBigInt()) {
206         if (y->IsBigInt()) {
207             return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
208         }
209         if (y->IsString()) {
210             JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
211             if (!yNumber->IsBigInt()) {
212                 return false;
213             }
214             return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
215         }
216         if (y->IsBoolean()) {
217             JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
218             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
219             return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
220         }
221         if (y->IsNumber()) {
222             JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
223             return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
224         }
225         if (y->IsHeapObject() && !y->IsSymbol()) {
226             JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
227             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
228             return Equal(thread, x, yPrimitive);
229         }
230         return false;
231     }
232 
233     if (x->IsHeapObject()) {
234         if (y->IsHeapObject()) {
235             // if same type, must call Type::StrictEqual()
236             JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
237             JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
238             if (xType == yType) {
239                 return StrictEqual(thread, x, y);
240             }
241         }
242         if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
243             JSHandle<JSTaggedValue> x_primitive(thread, ToPrimitive(thread, x));
244             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
245             return Equal(thread, x_primitive, y);
246         }
247         return false;
248     }
249 
250     if (x->IsNull() && y->IsNull()) {
251         return true;
252     }
253 
254     if (x->IsUndefined() && y->IsUndefined()) {
255         return true;
256     }
257 
258     if (x->IsNull() && y->IsUndefined()) {
259         return true;
260     }
261 
262     if (x->IsUndefined() && y->IsNull()) {
263         return true;
264     }
265 
266     return false;
267 }
268 
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)269 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
270                                         const JSHandle<JSTaggedValue> &y)
271 {
272     JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
273     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
274     JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
275     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
276     if (primX->IsString() && primY->IsString()) {
277         auto xString = static_cast<EcmaString *>(primX->GetTaggedObject());
278         auto yString = static_cast<EcmaString *>(primY->GetTaggedObject());
279         int result = EcmaStringAccessor::Compare(xString, yString);
280         if (result < 0) {
281             return ComparisonResult::LESS;
282         }
283         if (result == 0) {
284             return ComparisonResult::EQUAL;
285         }
286         return ComparisonResult::GREAT;
287     }
288     if (primX->IsBigInt()) {
289         if (primY->IsNumber()) {
290             JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
291             return BigInt::CompareWithNumber(bigint, primY);
292         } else if (primY->IsString()) {
293             JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
294             if (!bigY->IsBigInt()) {
295                 return ComparisonResult::UNDEFINED;
296             }
297             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
298         } else {
299             JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
300             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
301             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
302         }
303     }
304     if (primY->IsBigInt()) {
305         ComparisonResult res = Compare(thread, primY, primX);
306         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
307         if (res == ComparisonResult::GREAT) {
308             return ComparisonResult::LESS;
309         } else if (res == ComparisonResult::LESS) {
310             return ComparisonResult::GREAT;
311         }
312         return res;
313     }
314     JSTaggedNumber xNumber = ToNumber(thread, x);
315     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
316     JSTaggedNumber yNumber = ToNumber(thread, y);
317     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
318     return StrictNumberCompare(xNumber.GetNumber(), yNumber.GetNumber());
319 }
320 
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)321 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
322 {
323     if (x.IsNumber() && y.IsNumber()) {
324         return true;
325     }
326     if (x.IsBoolean() && y.IsBoolean()) {
327         return true;
328     }
329     if (x.IsString() && y.IsString()) {
330         return true;
331     }
332     if (x.IsHeapObject() && y.IsHeapObject()) {
333         return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
334     }
335 
336     return false;
337 }
338 
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)339 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
340                                          PreferredPrimitiveType type)
341 {
342     if (tagged->IsECMAObject()) {
343         EcmaVM *vm = thread->GetEcmaVM();
344         JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
345 
346         JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
347         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
348         if (!exoticToprim->IsUndefined()) {
349             JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
350             JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
351             EcmaRuntimeCallInfo *info =
352                 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
353             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
354             info->SetCallArg(value);
355             JSTaggedValue valueResult = JSFunction::Call(info);
356             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
357             if (!valueResult.IsECMAObject()) {
358                 return valueResult;
359             }
360             THROW_TYPE_ERROR_AND_RETURN(thread, "", JSTaggedValue::Exception());
361         } else {
362             type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
363             return OrdinaryToPrimitive(thread, tagged, type);
364         }
365     }
366     return tagged.GetTaggedValue();
367 }
368 
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)369 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
370                                                  PreferredPrimitiveType type)
371 {
372     static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
373     ASSERT(tagged->IsECMAObject());
374     auto globalConst = thread->GlobalConstants();
375     for (uint8_t i = 0; i < 2; i++) {  // 2: 2 means value has 2 target types, string or value.
376         JSHandle<JSTaggedValue> keyString;
377         if ((static_cast<uint8_t>(type) ^ i) != 0) {
378             keyString = globalConst->GetHandledToStringString();
379         } else {
380             keyString = globalConst->GetHandledValueOfString();
381         }
382         JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
383         if (entryfunc->IsCallable()) {
384             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
385             EcmaRuntimeCallInfo *info =
386                 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
387             JSTaggedValue valueResult = JSFunction::Call(info);
388             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
389             if (!valueResult.IsECMAObject()) {
390                 return valueResult;
391             }
392         }
393     }
394     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
395 }
396 
ToString(JSThread * thread,JSTaggedValue val)397 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
398 {
399     JSHandle<JSTaggedValue> tagged(thread, val);
400     return ToString(thread, tagged);
401 }
402 
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)403 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
404 {
405     if (tagged->IsString()) {
406         return JSHandle<EcmaString>(tagged);
407     }
408     auto globalConst = thread->GlobalConstants();
409     if (tagged->IsSpecial()) {
410         switch (tagged->GetRawData()) {
411             case VALUE_UNDEFINED: {
412                 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
413             }
414             case VALUE_NULL: {
415                 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
416             }
417             case VALUE_TRUE: {
418                 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
419             }
420             case VALUE_FALSE: {
421                 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
422             }
423             case VALUE_HOLE: {
424                 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
425             }
426             default:
427                 break;
428         }
429     }
430 
431     if (tagged->IsNumber()) {
432         return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
433     }
434 
435     if (tagged->IsBigInt()) {
436         JSHandle<BigInt> taggedValue(tagged);
437         return BigInt::ToString(thread, taggedValue);
438     }
439 
440     auto emptyStr = globalConst->GetHandledEmptyString();
441     if (tagged->IsECMAObject()) {
442         JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
443         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
444         return ToString(thread, primValue);
445     }
446     // Already Include Symbol
447     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
448 }
449 
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)450 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
451 {
452     if (tagged->IsNumber()) {
453         return tagged.GetTaggedValue();
454     }
455 
456     if (tagged->IsString()) {
457         JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
458         if (EcmaStringAccessor::StringsAreEqual(static_cast<EcmaString *>(tagged->GetTaggedObject()), *str)) {
459             return JSTaggedValue(-0.0);
460         }
461         JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
462         if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
463             return tmp.GetTaggedValue();
464         }
465     }
466     return JSTaggedValue::Undefined();
467 }
468 
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)469 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
470 {
471     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
472     if (tagged->IsInt() || tagged->IsDouble()) {
473         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
474     }
475 
476     switch (tagged->GetRawData()) {
477         case JSTaggedValue::VALUE_UNDEFINED: {
478             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
479                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
480         }
481         case JSTaggedValue::VALUE_HOLE: {
482             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
483                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
484         }
485         case JSTaggedValue::VALUE_NULL: {
486             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
487                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
488         }
489         case JSTaggedValue::VALUE_TRUE:
490         case JSTaggedValue::VALUE_FALSE: {
491             return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
492         }
493         default: {
494             break;
495         }
496     }
497 
498     if (tagged->IsECMAObject()) {
499         return JSHandle<JSObject>::Cast(tagged);
500     }
501     if (tagged->IsSymbol()) {
502         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
503     }
504     if (tagged->IsString()) {
505         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
506     }
507     if (tagged->IsBigInt()) {
508         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
509     }
510     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
511                                 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
512 }
513 
514 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)515 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
516                                            const JSHandle<JSTaggedValue> &key)
517 {
518     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
519         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
520         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
521         std::string message = "Cannot read property ";
522         message.append(keyStr).append(" of ").append(objStr);
523         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
524                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
525     }
526     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
527 
528     if (obj->IsJSProxy()) {
529         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
530     }
531     if (obj->IsTypedArray()) {
532         return JSTypedArray::GetProperty(thread, obj, key);
533     }
534     if (obj->IsModuleNamespace()) {
535         return ModuleNamespace::GetProperty(thread, obj, key);
536     }
537 
538     if (obj->IsSpecialContainer()) {
539         return GetJSAPIProperty(thread, obj, key);
540     }
541 
542     return JSObject::GetProperty(thread, obj, key);
543 }
544 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)545 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
546 {
547     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
548         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
549         std::string message = "Cannot read property ";
550         message.append(ToCString(key)).append(" of ").append(objStr);
551         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
552                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
553     }
554 
555     if (obj->IsJSProxy()) {
556         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
557         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
558     }
559 
560     if (obj->IsTypedArray()) {
561         return JSTypedArray::GetProperty(thread, obj, key);
562     }
563 
564     if (obj->IsSpecialContainer()) {
565         JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(key));
566         return GetJSAPIProperty(thread, obj, keyHandle);
567     }
568 
569     return JSObject::GetProperty(thread, obj, key);
570 }
571 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)572 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
573                                            const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
574 {
575     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
576         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
577         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
578         std::string message = "Cannot read property ";
579         message.append(keyStr).append(" of ").append(objStr);
580         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
581                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
582     }
583     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
584 
585     if (obj->IsJSProxy()) {
586         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
587     }
588     if (obj->IsTypedArray()) {
589         return JSTypedArray::GetProperty(thread, obj, key, receiver);
590     }
591 
592     if (obj->IsSpecialContainer()) {
593         return GetJSAPIProperty(thread, obj, key);
594     }
595 
596     return JSObject::GetProperty(thread, obj, key, receiver);
597 }
598 
599 // 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)600 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
601                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow)
602 {
603     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
604         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
605     }
606 
607     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
608 
609     // 4. Let success be O.[[Set]](P, V, O).
610     bool success = false;
611     if (obj->IsJSProxy()) {
612         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
613     } else if (obj->IsTypedArray()) {
614         success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
615     } else if (obj->IsModuleNamespace()) {
616         success = ModuleNamespace::SetProperty(thread, mayThrow);
617     } else if (obj->IsSpecialContainer()) {
618         success = SetJSAPIProperty(thread, obj, key, value);
619     } else {
620         success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
621     }
622     // 5. ReturnIfAbrupt(success).
623     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
624     // 6. If success is false and Throw is true, throw a TypeError exception.
625     // have done in JSObject::SetPropert.
626     return success;
627 }
628 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)629 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
630                                 const JSHandle<JSTaggedValue> &value, bool mayThrow)
631 {
632     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
633         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
634     }
635 
636     // 4. Let success be O.[[Set]](P, V, O).
637     bool success = false;
638     if (obj->IsJSProxy()) {
639         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
640         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
641     } else if (obj->IsTypedArray()) {
642         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
643         success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
644     } else if (obj->IsModuleNamespace()) {
645         success = ModuleNamespace::SetProperty(thread, mayThrow);
646     } else if (obj->IsSpecialContainer()) {
647         JSHandle<JSTaggedValue> keyHandle = JSHandle<JSTaggedValue>(thread, JSTaggedValue(key));
648         success = SetJSAPIProperty(thread, obj, keyHandle, value);
649     } else {
650         success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
651     }
652     // 5. ReturnIfAbrupt(success).
653     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
654     // 6. If success is false and Throw is true, throw a TypeError exception.
655     // have done in JSObject::SetPropert.
656     return success;
657 }
658 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)659 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
660                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
661                                 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
662 {
663     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
664         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
665     }
666 
667     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
668 
669     // 4. Let success be O.[[Set]](P, V, O).
670     bool success = false;
671     if (obj->IsJSProxy()) {
672         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
673     } else if (obj->IsTypedArray()) {
674         success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
675     } else if (obj->IsModuleNamespace()) {
676         success = ModuleNamespace::SetProperty(thread, mayThrow);
677     } else if (obj->IsSpecialContainer()) {
678         success = SetJSAPIProperty(thread, obj, key, value);
679     } else {
680         success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
681     }
682     // 5. ReturnIfAbrupt(success).
683     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
684     // 6. If success is false and Throw is true, throw a TypeError exception.
685     // have done in JSObject::SetPropert.
686     return success;
687 }
688 
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)689 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
690                                    const JSHandle<JSTaggedValue> &key)
691 {
692     if (obj->IsJSProxy()) {
693         return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
694     }
695 
696     if (obj->IsModuleNamespace()) {
697         return ModuleNamespace::DeleteProperty(thread, obj, key);
698     }
699 
700     if (obj->IsTypedArray()) {
701         return JSTypedArray::DeleteProperty(thread, obj, key);
702     }
703 
704     if (obj->IsSpecialContainer()) {
705         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
706     }
707 
708     return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
709 }
710 
711 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)712 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
713                                           const JSHandle<JSTaggedValue> &key)
714 {
715     if (!obj->IsECMAObject()) {
716         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
717     }
718     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
719 
720     // 3. Let success be O.[[Delete]](P).
721     bool success = DeleteProperty(thread, obj, key);
722 
723     // 4. ReturnIfAbrupt(success).
724     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
725     // 5. If success is false, throw a TypeError exception
726     if (!success) {
727         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
728     }
729     return success;
730 }
731 
732 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)733 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
734                                           const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
735 {
736     // 1. Assert: Type(O) is Object.
737     // 2. Assert: IsPropertyKey(P) is true.
738     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
739     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
740     // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
741     bool success = DefineOwnProperty(thread, obj, key, desc);
742     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
743     // 4. If success is false, throw a TypeError exception.
744     if (!success) {
745         THROW_TYPE_ERROR_AND_RETURN(thread, "", false);
746     }
747     return success;
748 }
749 
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)750 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
751                                       const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
752 {
753     if (obj->IsJSArray()) {
754         return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
755     }
756 
757     if (obj->IsJSProxy()) {
758         return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
759     }
760 
761     if (obj->IsTypedArray()) {
762         return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
763     }
764 
765     if (obj->IsModuleNamespace()) {
766         return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
767     }
768 
769     if (obj->IsSpecialContainer()) {
770         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
771     }
772 
773     return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
774 }
775 
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)776 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
777                                    const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
778 {
779     if (obj->IsJSProxy()) {
780         return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
781     }
782     if (obj->IsTypedArray()) {
783         return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
784     }
785     if (obj->IsModuleNamespace()) {
786         return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
787     }
788     if (obj->IsSpecialContainer()) {
789         return GetContainerProperty(thread, obj, key, desc);
790     }
791     return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
792 }
793 
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto)794 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
795                                  const JSHandle<JSTaggedValue> &proto)
796 {
797     if (obj->IsJSProxy()) {
798         return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
799     }
800     if (obj->IsModuleNamespace()) {
801         return ModuleNamespace::SetPrototype(obj, proto);
802     }
803     if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
804         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
805     }
806 
807     return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto);
808 }
809 
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)810 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
811 {
812     if (!obj->IsECMAObject()) {
813         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
814     }
815     if (obj->IsJSProxy()) {
816         return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
817     }
818     return JSObject::GetPrototype(JSHandle<JSObject>(obj));
819 }
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)820 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
821 {
822     if (obj->IsJSProxy()) {
823         return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
824     }
825     if (obj->IsModuleNamespace()) {
826         return ModuleNamespace::PreventExtensions();
827     }
828     return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
829 }
830 
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)831 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
832 {
833     if (obj->IsJSProxy()) {
834         return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
835     }
836     if (obj->IsTypedArray()) {
837         return JSTypedArray::OwnPropertyKeys(thread, obj);
838     }
839     if (obj->IsSpecialContainer()) {
840         return GetOwnContainerPropertyKeys(thread, obj);
841     }
842     if (obj->IsModuleNamespace()) {
843         return ModuleNamespace::OwnPropertyKeys(thread, obj);
844     }
845     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
846 }
847 
848 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)849 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
850                                 const JSHandle<JSTaggedValue> &key)
851 {
852     if (obj->IsJSProxy()) {
853         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
854     }
855     if (obj->IsTypedArray()) {
856         return JSTypedArray::HasProperty(thread, obj, key);
857     }
858     if (obj->IsModuleNamespace()) {
859         return ModuleNamespace::HasProperty(thread, obj, key);
860     }
861     if (obj->IsSpecialContainer()) {
862         return HasContainerProperty(thread, obj, key);
863     }
864     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
865 }
866 
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)867 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
868 {
869     if (obj->IsJSProxy()) {
870         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
871         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
872     }
873     if (obj->IsTypedArray()) {
874         JSHandle<JSTaggedValue> key_handle(thread, JSTaggedValue(key));
875         return JSTypedArray::HasProperty(thread, obj, key_handle);
876     }
877     if (obj->IsSpecialContainer()) {
878         return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
879     }
880     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
881 }
882 
883 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)884 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
885                                    const JSHandle<JSTaggedValue> &key)
886 {
887     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
888 
889     PropertyDescriptor desc(thread);
890     return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
891 }
892 
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)893 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
894 {
895     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
896 
897     PropertyDescriptor desc(thread);
898     return JSObject::GlobalGetOwnProperty(thread, key, desc);
899 }
900 
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)901 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
902 {
903     if (tagged->IsInt() && tagged->GetInt() >= 0) {
904         return JSTaggedNumber(tagged.GetTaggedValue());
905     }
906     if (tagged->IsUndefined()) {
907         return JSTaggedNumber(0);
908     }
909     JSTaggedNumber integerIndex = ToNumber(thread, tagged);
910     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
911     if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
912         return integerIndex;
913     }
914     double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
915     if (len < 0.0 || len > SAFE_NUMBER) {
916         THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
917                                      JSTaggedNumber::Exception());
918     }
919     return JSTaggedNumber(len);
920 }
921 
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)922 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
923 {
924     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
925 
926     if (obj->IsNumber()) {
927         return JSHandle<JSTaggedValue>(thread,
928                                        env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
929     }
930     if (obj->IsBoolean()) {
931         return JSHandle<JSTaggedValue>(thread,
932                                        env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
933     }
934     if (obj->IsString()) {
935         return JSHandle<JSTaggedValue>(thread,
936                                        env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
937     }
938     if (obj->IsSymbol()) {
939         return JSHandle<JSTaggedValue>(thread,
940                                        env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
941     }
942     if (obj->IsBigInt()) {
943         return JSHandle<JSTaggedValue>(thread,
944                                        env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
945     }
946     return obj;
947 }
948 
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)949 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
950 {
951     if (obj->IsUndefined()) {
952         return JSTaggedValue::Undefined();
953     }
954 
955     ASSERT(obj->IsECMAObject());
956     return JSTaggedValue::GetPrototype(thread, obj);
957 }
958 
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)959 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
960                                          const JSHandle<JSTaggedValue> &key)
961 {
962     auto *hclass = obj->GetTaggedObject()->GetClass();
963     JSType jsType = hclass->GetObjectType();
964     switch (jsType) {
965         case JSType::JS_API_ARRAY_LIST: {
966             return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
967         }
968         case JSType::JS_API_QUEUE: {
969             return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
970         }
971         case JSType::JS_API_PLAIN_ARRAY: {
972             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
973         }
974         case JSType::JS_API_DEQUE: {
975             return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
976         }
977         case JSType::JS_API_STACK: {
978             return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
979         }
980         case JSType::JS_API_LIST: {
981             JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
982             return list->Has(key.GetTaggedValue());
983         }
984         case JSType::JS_API_LINKED_LIST: {
985             JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
986             return linkedList->Has(key.GetTaggedValue());
987         }
988         case JSType::JS_API_HASH_MAP:
989         case JSType::JS_API_HASH_SET:
990         case JSType::JS_API_LIGHT_WEIGHT_MAP:
991         case JSType::JS_API_LIGHT_WEIGHT_SET:
992         case JSType::JS_API_TREE_MAP:
993         case JSType::JS_API_TREE_SET: {
994             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
995         }
996         case JSType::JS_API_VECTOR: {
997             return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
998         }
999         default: {
1000             UNREACHABLE();
1001         }
1002     }
1003     return false;
1004 }
1005 
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1006 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1007 {
1008     auto *hclass = obj->GetTaggedObject()->GetClass();
1009     JSType jsType = hclass->GetObjectType();
1010     switch (jsType) {
1011         case JSType::JS_API_ARRAY_LIST: {
1012             return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1013         }
1014         case JSType::JS_API_QUEUE: {
1015             return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1016         }
1017         case JSType::JS_API_PLAIN_ARRAY: {
1018             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1019         }
1020         case JSType::JS_API_DEQUE: {
1021             return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1022         }
1023         case JSType::JS_API_STACK: {
1024             return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1025         }
1026         case JSType::JS_API_LIST: {
1027             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1028         }
1029         case JSType::JS_API_LINKED_LIST: {
1030             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1031         }
1032         case JSType::JS_API_HASH_MAP:
1033         case JSType::JS_API_HASH_SET:
1034         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1035         case JSType::JS_API_LIGHT_WEIGHT_SET:
1036         case JSType::JS_API_TREE_MAP:
1037         case JSType::JS_API_TREE_SET: {
1038             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1039         }
1040         case JSType::JS_API_VECTOR: {
1041             return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1042         }
1043         default: {
1044             UNREACHABLE();
1045         }
1046     }
1047     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1048 }
1049 
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1050 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1051                                          const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1052 {
1053     if (key->IsInteger()) {
1054         auto *hclass = obj->GetTaggedObject()->GetClass();
1055         JSType jsType = hclass->GetObjectType();
1056         switch (jsType) {
1057             case JSType::JS_API_ARRAY_LIST: {
1058                 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1059             }
1060             case JSType::JS_API_QUEUE: {
1061                 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1062             }
1063             case JSType::JS_API_DEQUE: {
1064                 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1065             }
1066             case JSType::JS_API_STACK: {
1067                 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1068             }
1069             case JSType::JS_API_LIST: {
1070                 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1071             }
1072             case JSType::JS_API_LINKED_LIST: {
1073                 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1074             }
1075             case JSType::JS_API_PLAIN_ARRAY: {
1076                 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1077             }
1078             case JSType::JS_API_VECTOR: {
1079                 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1080             }
1081             default: {
1082                 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1083             }
1084         }
1085     } else {
1086         return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1087     }
1088     return false;
1089 }
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1090 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1091 {
1092     // 1. Let primValue be ? ToPrimitive(value, number)
1093     JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
1094     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1095     // 2. If Type(primValue) is BigInt, return primValue.
1096     if (primValue->IsBigInt()) {
1097         return primValue;
1098     }
1099     // 3. Return ? ToNumber(primValue).
1100     JSTaggedNumber number = ToNumber(thread, primValue);
1101     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1102     JSHandle<JSTaggedValue> value(thread, number);
1103     return value;
1104 }
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1105 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1106                                                 const JSHandle<JSTaggedValue> &key)
1107 {
1108     if (key->IsInteger()) {
1109         auto *hclass = obj->GetTaggedObject()->GetClass();
1110         JSType jsType = hclass->GetObjectType();
1111         switch (jsType) {
1112             case JSType::JS_API_ARRAY_LIST: {
1113                 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1114             }
1115             case JSType::JS_API_LIST: {
1116                 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1117             }
1118             case JSType::JS_API_LINKED_LIST: {
1119                 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1120             }
1121             case JSType::JS_API_QUEUE: {
1122                 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1123             }
1124             case JSType::JS_API_DEQUE: {
1125                 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1126             }
1127             case JSType::JS_API_STACK: {
1128                 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1129             }
1130             case JSType::JS_API_PLAIN_ARRAY: {
1131                 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1132             }
1133             case JSType::JS_API_VECTOR: {
1134                 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1135             }
1136             default: {
1137                 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1138             }
1139         }
1140     } else {
1141         return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1142     }
1143     return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1144 }
1145 
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1146 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1147                                      const JSHandle<JSTaggedValue> &key,
1148                                      const JSHandle<JSTaggedValue> &value)
1149 {
1150     if (key->IsInteger()) {
1151         auto *hclass = obj->GetTaggedObject()->GetClass();
1152         JSType jsType = hclass->GetObjectType();
1153         switch (jsType) {
1154             case JSType::JS_API_ARRAY_LIST: {
1155                 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1156             }
1157             case JSType::JS_API_LIST: {
1158                 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1159             }
1160             case JSType::JS_API_LINKED_LIST: {
1161                 return JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1162             }
1163             case JSType::JS_API_QUEUE: {
1164                 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1165             }
1166             case JSType::JS_API_DEQUE: {
1167                 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1168             }
1169             case JSType::JS_API_STACK: {
1170                 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1171             }
1172             case JSType::JS_API_PLAIN_ARRAY: {
1173                 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1174             }
1175             case JSType::JS_API_VECTOR: {
1176                 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1177             }
1178             default: {
1179                 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1180             }
1181         }
1182     } else {
1183         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1184     }
1185     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1186 }
1187 }  // namespace panda::ecmascript
1188