• 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         JSHandle<JSFunction> protoFunc = JSHandle<JSFunction>::Cast(proto);
818         JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
819         JSTaggedValue protoOrHClass(protoFunc->GetProtoOrHClass());
820         if (objProtoOrHClass.IsJSHClass() && protoOrHClass.IsJSHClass() && objProtoOrHClass != protoOrHClass) {
821             JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
822             objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
823         }
824     }
825 
826     return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto);
827 }
828 
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)829 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
830 {
831     if (!obj->IsECMAObject()) {
832         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
833     }
834     if (obj->IsJSProxy()) {
835         return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
836     }
837     return JSObject::GetPrototype(JSHandle<JSObject>(obj));
838 }
839 
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)840 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
841 {
842     if (obj->IsJSProxy()) {
843         return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
844     }
845     if (obj->IsModuleNamespace()) {
846         return ModuleNamespace::PreventExtensions();
847     }
848     return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
849 }
850 
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)851 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
852 {
853     if (obj->IsJSProxy()) {
854         return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
855     }
856     if (obj->IsTypedArray()) {
857         return JSTypedArray::OwnPropertyKeys(thread, obj);
858     }
859     if (obj->IsSpecialContainer()) {
860         return GetOwnContainerPropertyKeys(thread, obj);
861     }
862     if (obj->IsModuleNamespace()) {
863         return ModuleNamespace::OwnPropertyKeys(thread, obj);
864     }
865     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
866 }
867 
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)868 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
869                                                         const JSHandle<JSTaggedValue> &obj, uint32_t filter)
870 {
871     if (obj->IsJSProxy()) {
872         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support JSProxy yet";
873         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
874     }
875     if (obj->IsTypedArray()) {
876         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
877         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
878     }
879     if (obj->IsSpecialContainer()) {
880         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
881         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
882     }
883     if (obj->IsModuleNamespace()) {
884         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
885         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
886     }
887     return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
888 }
889 
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)890 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
891 {
892     ASSERT(!obj->IsJSProxy());
893     if (obj->IsTypedArray()) {
894         return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
895     }
896     if (obj->IsSpecialContainer()) {
897         return GetOwnContainerEnumPropertyKeys(thread, obj);
898     }
899     if (obj->IsModuleNamespace()) {
900         return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
901     }
902     return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
903 }
904 
905 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)906 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
907                                 const JSHandle<JSTaggedValue> &key)
908 {
909     if (obj->IsJSProxy()) {
910         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
911     }
912     if (obj->IsTypedArray()) {
913         return JSTypedArray::HasProperty(thread, obj, key);
914     }
915     if (obj->IsModuleNamespace()) {
916         return ModuleNamespace::HasProperty(thread, obj, key);
917     }
918     if (obj->IsSpecialContainer()) {
919         return HasContainerProperty(thread, obj, key);
920     }
921     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
922 }
923 
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)924 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
925 {
926     if (obj->IsJSProxy()) {
927         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
928         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
929     }
930     if (obj->IsTypedArray()) {
931         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
932         return JSTypedArray::HasProperty(thread, obj, keyHandle);
933     }
934     if (obj->IsSpecialContainer()) {
935         return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
936     }
937     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
938 }
939 
940 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)941 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
942                                    const JSHandle<JSTaggedValue> &key)
943 {
944     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
945 
946     PropertyDescriptor desc(thread);
947     return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
948 }
949 
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)950 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
951 {
952     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
953 
954     PropertyDescriptor desc(thread);
955     return JSObject::GlobalGetOwnProperty(thread, key, desc);
956 }
957 
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)958 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
959 {
960     // 1. If v is an Object, return true.
961     if (tagged->IsECMAObject()) {
962         return true;
963     }
964     // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
965     if (tagged->IsSymbol()) {
966         JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
967         auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
968         JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
969         if (key.IsUndefined()) {
970             return true;
971         }
972     }
973     // 3. Return false.
974     return false;
975 }
976 
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)977 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
978 {
979     if (tagged->IsInt() && tagged->GetInt() >= 0) {
980         return JSTaggedNumber(tagged.GetTaggedValue());
981     }
982     if (tagged->IsUndefined()) {
983         return JSTaggedNumber(0);
984     }
985     JSTaggedNumber integerIndex = ToNumber(thread, tagged);
986     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
987     if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
988         return integerIndex;
989     }
990     double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
991     if (len < 0.0 || len > SAFE_NUMBER) {
992         THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
993                                      JSTaggedNumber::Exception());
994     }
995     return JSTaggedNumber(len);
996 }
997 
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)998 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
999 {
1000     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1001 
1002     if (obj->IsNumber()) {
1003         return JSHandle<JSTaggedValue>(thread,
1004                                        env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1005     }
1006     if (obj->IsBoolean()) {
1007         return JSHandle<JSTaggedValue>(thread,
1008                                        env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1009     }
1010     if (obj->IsString()) {
1011         return JSHandle<JSTaggedValue>(thread,
1012                                        env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1013     }
1014     if (obj->IsSymbol()) {
1015         return JSHandle<JSTaggedValue>(thread,
1016                                        env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1017     }
1018     if (obj->IsBigInt()) {
1019         return JSHandle<JSTaggedValue>(thread,
1020                                        env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1021     }
1022     return obj;
1023 }
1024 
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1025 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1026 {
1027     if (obj->IsUndefined()) {
1028         return JSTaggedValue::Undefined();
1029     }
1030 
1031     ASSERT(obj->IsECMAObject());
1032     return JSTaggedValue::GetPrototype(thread, obj);
1033 }
1034 
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1035 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1036                                          const JSHandle<JSTaggedValue> &key)
1037 {
1038     auto *hclass = obj->GetTaggedObject()->GetClass();
1039     JSType jsType = hclass->GetObjectType();
1040     switch (jsType) {
1041         case JSType::JS_API_ARRAY_LIST: {
1042             return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1043         }
1044         case JSType::JS_API_QUEUE: {
1045             return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1046         }
1047         case JSType::JS_API_PLAIN_ARRAY: {
1048             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1049         }
1050         case JSType::JS_API_DEQUE: {
1051             return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1052         }
1053         case JSType::JS_API_STACK: {
1054             return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1055         }
1056         case JSType::JS_API_LIST: {
1057             JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1058             return list->Has(key.GetTaggedValue());
1059         }
1060         case JSType::JS_API_LINKED_LIST: {
1061             JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1062             return linkedList->Has(key.GetTaggedValue());
1063         }
1064         case JSType::JS_API_HASH_MAP:
1065         case JSType::JS_API_HASH_SET:
1066         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1067         case JSType::JS_API_LIGHT_WEIGHT_SET:
1068         case JSType::JS_API_TREE_MAP:
1069         case JSType::JS_API_TREE_SET: {
1070             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1071         }
1072         case JSType::JS_API_VECTOR: {
1073             return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1074         }
1075         default: {
1076             LOG_ECMA(FATAL) << "this branch is unreachable";
1077             UNREACHABLE();
1078         }
1079     }
1080     return false;
1081 }
1082 
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1083 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1084 {
1085     auto *hclass = obj->GetTaggedObject()->GetClass();
1086     JSType jsType = hclass->GetObjectType();
1087     switch (jsType) {
1088         case JSType::JS_API_ARRAY_LIST: {
1089             return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1090         }
1091         case JSType::JS_API_QUEUE: {
1092             return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1093         }
1094         case JSType::JS_API_PLAIN_ARRAY: {
1095             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1096         }
1097         case JSType::JS_API_DEQUE: {
1098             return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1099         }
1100         case JSType::JS_API_STACK: {
1101             return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1102         }
1103         case JSType::JS_API_LIST: {
1104             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1105         }
1106         case JSType::JS_API_LINKED_LIST: {
1107             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1108         }
1109         case JSType::JS_API_HASH_MAP:
1110         case JSType::JS_API_HASH_SET:
1111         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1112         case JSType::JS_API_LIGHT_WEIGHT_SET:
1113         case JSType::JS_API_TREE_MAP:
1114         case JSType::JS_API_TREE_SET: {
1115             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1116         }
1117         case JSType::JS_API_VECTOR: {
1118             return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1119         }
1120         default: {
1121             LOG_ECMA(FATAL) << "this branch is unreachable";
1122             UNREACHABLE();
1123         }
1124     }
1125     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1126 }
1127 
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1128 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1129     const JSHandle<JSTaggedValue> &obj)
1130 {
1131     auto *hclass = obj->GetTaggedObject()->GetClass();
1132     JSType jsType = hclass->GetObjectType();
1133     switch (jsType) {
1134         case JSType::JS_API_QUEUE: {
1135             return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1136         }
1137         case JSType::JS_API_DEQUE: {
1138             return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1139         }
1140         case JSType::JS_API_LIST: {
1141             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1142         }
1143         case JSType::JS_API_LINKED_LIST: {
1144             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1145         }
1146         case JSType::JS_API_VECTOR:
1147         case JSType::JS_API_STACK:
1148         case JSType::JS_API_ARRAY_LIST:
1149         case JSType::JS_API_PLAIN_ARRAY:
1150         case JSType::JS_API_HASH_MAP:
1151         case JSType::JS_API_HASH_SET:
1152         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1153         case JSType::JS_API_LIGHT_WEIGHT_SET:
1154         case JSType::JS_API_TREE_MAP:
1155         case JSType::JS_API_TREE_SET: {
1156             return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1157         }
1158         default: {
1159             UNREACHABLE();
1160         }
1161     }
1162     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1163 }
1164 
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1165 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1166                                          const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1167 {
1168     if (key->IsInteger()) {
1169         auto *hclass = obj->GetTaggedObject()->GetClass();
1170         JSType jsType = hclass->GetObjectType();
1171         switch (jsType) {
1172             case JSType::JS_API_ARRAY_LIST: {
1173                 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1174             }
1175             case JSType::JS_API_QUEUE: {
1176                 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1177             }
1178             case JSType::JS_API_DEQUE: {
1179                 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1180             }
1181             case JSType::JS_API_STACK: {
1182                 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1183             }
1184             case JSType::JS_API_LIST: {
1185                 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1186             }
1187             case JSType::JS_API_LINKED_LIST: {
1188                 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1189             }
1190             case JSType::JS_API_PLAIN_ARRAY: {
1191                 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1192             }
1193             case JSType::JS_API_VECTOR: {
1194                 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1195             }
1196             default: {
1197                 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1198             }
1199         }
1200     } else {
1201         return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1202     }
1203     return false;
1204 }
1205 
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1206 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1207 {
1208     // 1. Let primValue be ? ToPrimitive(value, number)
1209     JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
1210     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1211     // 2. If Type(primValue) is BigInt, return primValue.
1212     if (primValue->IsBigInt()) {
1213         return primValue;
1214     }
1215     // 3. Return ? ToNumber(primValue).
1216     JSTaggedNumber number = ToNumber(thread, primValue);
1217     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1218     JSHandle<JSTaggedValue> value(thread, number);
1219     return value;
1220 }
1221 
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1222 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1223                                                 const JSHandle<JSTaggedValue> &key)
1224 {
1225     if (key->IsInteger()) {
1226         auto *hclass = obj->GetTaggedObject()->GetClass();
1227         JSType jsType = hclass->GetObjectType();
1228         switch (jsType) {
1229             case JSType::JS_API_ARRAY_LIST: {
1230                 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1231             }
1232             case JSType::JS_API_LIST: {
1233                 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1234             }
1235             case JSType::JS_API_LINKED_LIST: {
1236                 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1237             }
1238             case JSType::JS_API_QUEUE: {
1239                 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1240             }
1241             case JSType::JS_API_DEQUE: {
1242                 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1243             }
1244             case JSType::JS_API_STACK: {
1245                 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1246             }
1247             case JSType::JS_API_PLAIN_ARRAY: {
1248                 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1249             }
1250             case JSType::JS_API_VECTOR: {
1251                 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1252             }
1253             default: {
1254                 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1255             }
1256         }
1257     } else {
1258         return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1259     }
1260     return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1261 }
1262 
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1263 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1264                                      const JSHandle<JSTaggedValue> &key,
1265                                      const JSHandle<JSTaggedValue> &value)
1266 {
1267     if (key->IsInteger()) {
1268         auto *hclass = obj->GetTaggedObject()->GetClass();
1269         JSType jsType = hclass->GetObjectType();
1270         switch (jsType) {
1271             case JSType::JS_API_ARRAY_LIST: {
1272                 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1273             }
1274             case JSType::JS_API_LIST: {
1275                 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1276             }
1277             case JSType::JS_API_LINKED_LIST: {
1278                 return JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1279             }
1280             case JSType::JS_API_QUEUE: {
1281                 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1282             }
1283             case JSType::JS_API_DEQUE: {
1284                 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1285             }
1286             case JSType::JS_API_STACK: {
1287                 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1288             }
1289             case JSType::JS_API_PLAIN_ARRAY: {
1290                 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1291             }
1292             case JSType::JS_API_VECTOR: {
1293                 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1294             }
1295             default: {
1296                 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1297             }
1298         }
1299     } else {
1300         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1301     }
1302     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1303 }
1304 }  // namespace panda::ecmascript
1305