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