• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "common_components/objects/string_table/integer_cache.h"
19 #include "ecmascript/ecma_string-inl.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_bitvector.h"
24 #include "ecmascript/js_api/js_api_buffer.h"
25 #include "ecmascript/js_api/js_api_deque.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_date.h"
33 #include "ecmascript/js_primitive_ref.h"
34 #include "ecmascript/js_typed_array.h"
35 #include "ecmascript/message_string.h"
36 #include "ecmascript/shared_objects/js_shared_array.h"
37 #include "ecmascript/symbol_table.h"
38 
39 namespace panda::ecmascript {
40 
ToBoolean() const41 bool JSTaggedValue::ToBoolean() const
42 {
43     if (IsInt()) {
44         return GetInt() != 0;
45     }
46     if (IsDouble()) {
47         double d = GetDouble();
48         return !std::isnan(d) && d != 0;
49     }
50     switch (GetRawData()) {
51         case JSTaggedValue::VALUE_UNDEFINED:
52             [[fallthrough]];
53         case JSTaggedValue::VALUE_HOLE:
54             [[fallthrough]];
55         case JSTaggedValue::VALUE_NULL:
56             [[fallthrough]];
57         case JSTaggedValue::VALUE_FALSE: {
58             return false;
59         }
60         case JSTaggedValue::VALUE_TRUE: {
61             return true;
62         }
63         default: {
64             break;
65         }
66     }
67 
68     if (IsBigInt()) {
69         BigInt *bigint = BigInt::Cast(GetTaggedObject());
70         return !bigint->IsZero();
71     }
72     if (IsHeapObject()) {
73         TaggedObject *obj = GetTaggedObject();
74         if (IsString()) {
75             auto str = static_cast<EcmaString *>(obj);
76             return EcmaStringAccessor(str).GetLength() != 0;
77         }
78         return true;
79     }
80     LOG_ECMA(FATAL) << "this branch is unreachable";
81     UNREACHABLE();
82 }
83 
ToNumber(JSThread * thread,JSTaggedValue tagged)84 JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, JSTaggedValue tagged)
85 {
86     {
87         DISALLOW_GARBAGE_COLLECTION;
88         if (tagged.IsInt() || tagged.IsDouble()) {
89             return JSTaggedNumber(tagged);
90         }
91         switch (tagged.GetRawData()) {
92             case JSTaggedValue::VALUE_UNDEFINED:
93             case JSTaggedValue::VALUE_HOLE: {
94                 return JSTaggedNumber(base::NAN_VALUE);
95             }
96             case JSTaggedValue::VALUE_TRUE: {
97                 return JSTaggedNumber(1);
98             }
99             case JSTaggedValue::VALUE_FALSE:
100             case JSTaggedValue::VALUE_NULL: {
101                 return JSTaggedNumber(0);
102             }
103             default: {
104                 break;
105             }
106         }
107         if (tagged.IsString()) {
108             return StringToNumber(thread, tagged);
109         }
110     }
111     if (tagged.IsECMAObject()) {
112         JSHandle<JSTaggedValue>taggedHandle(thread, tagged);
113         JSTaggedValue primValue = ToPrimitive(thread, taggedHandle, PREFER_NUMBER);
114         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
115         return ToNumber(thread, primValue);
116     }
117     if (tagged.IsSymbol()) {
118         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
119     }
120     if (tagged.IsBigInt()) {
121         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
122     }
123     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
124 }
125 
ToNumber(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)126 JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
127 {
128     return ToNumber(thread, tagged.GetTaggedValue());
129 }
130 
ToBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)131 JSTaggedValue JSTaggedValue::ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
132 {
133     JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged));
134     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
135     switch (primValue->GetRawData()) {
136         case JSTaggedValue::VALUE_UNDEFINED:
137         case JSTaggedValue::VALUE_NULL: {
138             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a undefine or null value to a BigInt",
139                                         JSTaggedValue::Exception());
140         }
141         case JSTaggedValue::VALUE_TRUE: {
142             return BigInt::Int32ToBigInt(thread, 1).GetTaggedValue();
143         }
144         case JSTaggedValue::VALUE_FALSE: {
145             return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
146         }
147         default: {
148             break;
149         }
150     }
151 
152     if (primValue->IsNumber()) {
153         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Number value to a BigInt", JSTaggedNumber::Exception());
154     }
155     if (primValue->IsString()) {
156         JSHandle<JSTaggedValue> value(thread, base::NumberHelper::StringToBigInt(thread, primValue));
157         if (value->IsBigInt()) {
158             return value.GetTaggedValue();
159         }
160         THROW_SYNTAX_ERROR_AND_RETURN(thread, "Cannot convert string to a BigInt,"
161                                       "because not allow Infinity, decimal points, or exponents",
162                                       JSTaggedValue::Exception());
163     }
164     if (primValue->IsSymbol()) {
165         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a BigInt", JSTaggedNumber::Exception());
166     }
167     if (primValue->IsBigInt()) {
168         return primValue.GetTaggedValue();
169     }
170     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a BigInt", JSTaggedNumber::Exception());
171 }
172 
ToBigInt64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)173 JSTaggedValue JSTaggedValue::ToBigInt64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
174 {
175     JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
176     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
177     JSHandle<BigInt> tVal = BigInt::GetUint64MaxBigInt(thread);
178     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
179     JSHandle<BigInt> int64bitVal = BigInt::FloorMod(thread, value, tVal);
180     JSHandle<BigInt> resValue = BigInt::GetInt64MaxBigInt(thread);
181     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
182     if (!BigInt::LessThan(int64bitVal.GetTaggedValue(), resValue.GetTaggedValue())) {
183         return BigInt::Subtract(thread, int64bitVal, tVal).GetTaggedValue();
184     } else {
185         return int64bitVal.GetTaggedValue();
186     }
187 }
188 
ToBigUint64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)189 JSTaggedValue JSTaggedValue::ToBigUint64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
190 {
191     JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
192     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
193     bool signFlag = value->GetSign();
194     uint32_t len = value->GetLength();
195     if (!signFlag && len <= 2) { // 2:2 int equal int64
196         return value.GetTaggedValue();
197     }
198     JSHandle<BigInt> tVal = BigInt::GetUint64MaxBigInt(thread);
199     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
200     return BigInt::FloorMod(thread, value, tVal).GetTaggedValue();
201 }
202 
ToInteger(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)203 JSTaggedNumber JSTaggedValue::ToInteger(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
204 {
205     JSTaggedNumber number = ToNumber(thread, tagged);
206     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
207 
208     return JSTaggedNumber(base::NumberHelper::TruncateDouble(number.GetNumber()));
209 }
210 
ToInt32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)211 int32_t JSTaggedValue::ToInt32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
212 {
213     JSTaggedNumber number = ToNumber(thread, tagged);
214     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
215     return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT32_BITS);
216 }
217 
ToUint32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)218 uint32_t JSTaggedValue::ToUint32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
219 {
220     return ToInt32(thread, tagged);
221 }
222 
ToInt16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)223 int16_t JSTaggedValue::ToInt16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
224 {
225     JSTaggedNumber number = ToNumber(thread, tagged);
226     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
227 
228     return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT16_BITS);
229 }
230 
ToUint16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)231 uint16_t JSTaggedValue::ToUint16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
232 {
233     return ToInt16(thread, tagged);
234 }
235 
ToInt8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)236 int8_t JSTaggedValue::ToInt8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
237 {
238     JSTaggedNumber number = ToNumber(thread, tagged);
239     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
240 
241     return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT8_BITS);
242 }
243 
ToUint8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)244 uint8_t JSTaggedValue::ToUint8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
245 {
246     return ToInt8(thread, tagged);
247 }
248 
ToUint8Clamp(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)249 uint8_t JSTaggedValue::ToUint8Clamp(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
250 {
251     JSTaggedNumber number = ToNumber(thread, tagged);
252     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
253 
254     double d = number.GetNumber();
255     if (std::isnan(d) || d <= 0) {
256         return 0;
257     }
258     if (d >= UINT8_MAX) {
259         return UINT8_MAX;
260     }
261 
262     return lrint(d);
263 }
264 
ToLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)265 JSTaggedNumber JSTaggedValue::ToLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
266 {
267     JSTaggedNumber len = ToInteger(thread, tagged);
268     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
269     if (len.GetNumber() < 0.0) {
270         return JSTaggedNumber(static_cast<double>(0));
271     }
272     if (len.GetNumber() > SAFE_NUMBER) {
273         return JSTaggedNumber(static_cast<double>(SAFE_NUMBER));
274     }
275     return len;
276 }
277 
IsPrimitive(uint8_t primitiveType) const278 bool JSTaggedValue::IsPrimitive(uint8_t primitiveType) const
279 {
280     if (((primitiveType & static_cast<uint8_t>(PrimitiveType::PRIMITIVE_BOOLEAN)) != 0) &&
281         IsBoolean()) {
282         return true;
283     }
284     if (((primitiveType & static_cast<uint8_t>(PrimitiveType::PRIMITIVE_NUMBER)) != 0) &&
285         IsNumber()) {
286         return true;
287     }
288     if (((primitiveType & static_cast<uint8_t>(PrimitiveType::PRIMITIVE_STRING)) != 0) &&
289         IsString()) {
290         return true;
291     }
292     if (((primitiveType & static_cast<uint8_t>(PrimitiveType::PRIMITIVE_SYMBOL)) != 0) &&
293         IsSymbol()) {
294         return true;
295     }
296     if (((primitiveType & static_cast<uint8_t>(PrimitiveType::PRIMITIVE_BIGINT)) != 0) &&
297         IsBigInt()) {
298         return true;
299     }
300     return false;
301 }
302 
303 // ecma6 7.2 Testing and Comparison Operations
RequireObjectCoercible(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,const char * message)304 JSHandle<JSTaggedValue> JSTaggedValue::RequireObjectCoercible(JSThread *thread,
305                                                               const JSHandle<JSTaggedValue> &tagged,
306                                                               const char *message)
307 {
308     if (tagged->IsUndefinedOrNull()) {
309         THROW_TYPE_ERROR_AND_RETURN(thread, message, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
310     }
311     return tagged;
312 }
313 
GetTypeString(JSThread * thread,PreferredPrimitiveType type)314 JSHandle<EcmaString> GetTypeString(JSThread *thread, PreferredPrimitiveType type)
315 {
316     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
317     if (type == NO_PREFERENCE) {
318         return JSHandle<EcmaString>::Cast(globalConst->GetHandledDefaultString());
319     }
320     if (type == PREFER_NUMBER) {
321         return JSHandle<EcmaString>::Cast(globalConst->GetHandledNumberString());
322     }
323     return JSHandle<EcmaString>::Cast(globalConst->GetHandledStringString());
324 }
325 
IsInSharedHeap() const326 bool JSTaggedValue::IsInSharedHeap() const
327 {
328     if (IsHeapObject()) {
329         // SharedHeap flags could move to high 32 bits in the object header.
330         if (LIKELY(!g_isEnableCMCGC)) {
331             Region *region = Region::ObjectAddressToRange(value_);
332             return region->InSharedHeap();
333         } else {
334             TaggedObject *obj = GetHeapObject();
335             if (IsJSHClass()) {
336                 return JSHClass::Cast(obj)->IsJSShared();
337             }
338             return obj->IsInSharedHeap();
339         }
340     }
341     return false;
342 }
343 
ToPropertyKey(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)344 JSHandle<JSTaggedValue> JSTaggedValue::ToPropertyKey(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
345 {
346     if (tagged->IsStringOrSymbol() || tagged->IsNumber()) {
347         return tagged;
348     }
349     JSHandle<JSTaggedValue> key(thread, ToPrimitive(thread, tagged, PREFER_STRING));
350     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
351     if (key->IsSymbol()) {
352         return key;
353     }
354     JSHandle<EcmaString> string = ToString(thread, key);
355     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
356     return JSHandle<JSTaggedValue>::Cast(string);
357 }
358 
IsInteger() const359 bool JSTaggedValue::IsInteger() const
360 {
361     if (!IsNumber()) {
362         return false;
363     }
364 
365     if (IsInt()) {
366         return true;
367     }
368 
369     double thisValue = GetDouble();
370     // If argument is NaN, +∞, or -∞, return false.
371     if (!std::isfinite(thisValue)) {
372         return false;
373     }
374 
375     // If floor(abs(argument)) ≠ abs(argument), return false.
376     if (std::floor(std::abs(thisValue)) != std::abs(thisValue)) {
377         return false;
378     }
379 
380     return true;
381 }
382 
IsJSCOWArray(const JSThread * thread) const383 bool JSTaggedValue::IsJSCOWArray(const JSThread *thread) const
384 {
385     // Elements of JSArray are shared and properties are not yet.
386     return IsJSArray() && JSArray::Cast(GetTaggedObject())->GetElements(thread).IsCOWArray();
387 }
388 
IsStableJSArray(JSThread * thread) const389 bool JSTaggedValue::IsStableJSArray(JSThread *thread) const
390 {
391     return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArray() &&
392            !thread->GetEcmaVM()->GetGlobalEnv()->IsArrayPrototypeChangedGuardiansInvalid() &&
393            !GetTaggedObject()->GetClass()->IsJSArrayPrototypeModifiedFromBitField();
394 }
395 
IsStableJSArguments(JSThread * thread) const396 bool JSTaggedValue::IsStableJSArguments(JSThread *thread) const
397 {
398     return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArguments() &&
399            !thread->GetEcmaVM()->GetGlobalEnv()->IsArrayPrototypeChangedGuardiansInvalid();
400 }
401 
IsTaggedArray() const402 bool JSTaggedValue::IsTaggedArray() const
403 {
404     return IsHeapObject() && GetTaggedObject()->GetClass()->IsTaggedArray();
405 }
406 
IsJSProxy() const407 bool JSTaggedValue::IsJSProxy() const
408 {
409     return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxy();
410 }
411 
IsGeneratorObject() const412 bool JSTaggedValue::IsGeneratorObject() const
413 {
414     return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject();
415 }
416 
IsGeneratorContext() const417 bool JSTaggedValue::IsGeneratorContext() const
418 {
419     return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext();
420 }
421 
WithinInt32(bool acceptsNegativeZero) const422 bool JSTaggedValue::WithinInt32(bool acceptsNegativeZero) const
423 {
424     if (IsInt()) {
425         return true;
426     }
427     if (!IsDouble()) {
428         return false;
429     }
430     double doubleValue = GetDouble();
431     if (base::bit_cast<int64_t>(doubleValue) == base::bit_cast<int64_t>(-0.0)) {
432         return acceptsNegativeZero;
433     }
434     // NaN and INF -> 0
435     int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
436     return doubleValue == static_cast<double>(intvalue);
437 }
438 
IsZero() const439 bool JSTaggedValue::IsZero() const
440 {
441     if (GetRawData() == VALUE_ZERO) {
442         return true;
443     }
444     if (IsDouble()) {
445         const double limit = 1e-8;
446         return (std::abs(GetDouble() - 0.0) <= limit);
447     }
448     return false;
449 }
450 
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)451 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
452 {
453     if (x->IsNumber()) {
454         return EqualNumber(thread, x, y);
455     }
456 
457     if (x->IsString()) {
458         return EqualString(thread, x, y);
459     }
460 
461     if (x->IsBoolean()) {
462         JSTaggedNumber xNumber = ToNumber(thread, x);
463         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
464         return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
465     }
466 
467     if (x->IsSymbol()) {
468         return EqualSymbol(thread, x, y);
469     }
470 
471     if (x->IsBigInt()) {
472         return EqualBigInt(thread, x, y);
473     }
474 
475     if (x->IsHeapObject()) {
476         return EqualHeapObject(thread, x, y);
477     }
478 
479     return EqualNullOrUndefined(x, y);
480 }
481 
EqualNumber(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)482 bool JSTaggedValue::EqualNumber(JSThread *thread, const JSHandle<JSTaggedValue> &x,
483                                 const JSHandle<JSTaggedValue> &y)
484 {
485     if (y->IsNumber()) {
486         return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
487     }
488     if (y->IsString()) {
489             JSTaggedNumber yNumber = ToNumber(thread, y);
490             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
491             return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
492     }
493     if (y->IsBoolean()) {
494         JSTaggedNumber yNumber = ToNumber(thread, y);
495         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
496         return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
497     }
498     if (y->IsBigInt()) {
499         return Equal(thread, y, x);
500     }
501     if (y->IsECMAObject()) {
502         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
503         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
504         return Equal(thread, x, yPrimitive);
505     }
506     return false;
507 }
508 
EqualString(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)509 bool JSTaggedValue::EqualString(JSThread *thread, const JSHandle<JSTaggedValue> &x,
510                                 const JSHandle<JSTaggedValue> &y)
511 {
512     if (y->IsString()) {
513         return EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(),
514                                                    JSHandle<EcmaString>(x),
515                                                    JSHandle<EcmaString>(y));
516     }
517     if (y->IsNumber()) {
518         JSTaggedNumber xNumber = ToNumber(thread, x);
519         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
520         return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
521     }
522     if (y->IsBoolean()) {
523         JSTaggedNumber xNumber = ToNumber(thread, x);
524         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
525         JSTaggedNumber yNumber = ToNumber(thread, y);
526         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
527         return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
528     }
529     if (y->IsBigInt()) {
530         return Equal(thread, y, x);
531     }
532     if (y->IsECMAObject()) {
533         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
534         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
535         return Equal(thread, x, yPrimitive);
536     }
537     return false;
538 }
539 
EqualSymbol(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)540 bool JSTaggedValue::EqualSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &x,
541                                 const JSHandle<JSTaggedValue> &y)
542 {
543     if (y->IsSymbol()) {
544         return x.GetTaggedValue() == y.GetTaggedValue();
545     }
546     if (y->IsBigInt() || y->IsString()) {
547         return false;
548     }
549     if (y->IsECMAObject()) {
550         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
551         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
552         return Equal(thread, x, yPrimitive);
553     }
554     return false;
555 }
556 
EqualBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)557 bool JSTaggedValue::EqualBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &x,
558                                 const JSHandle<JSTaggedValue> &y)
559 {
560     if (y->IsBigInt()) {
561         return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
562     }
563     if (y->IsString()) {
564         JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
565         if (!yNumber->IsBigInt()) {
566             return false;
567         }
568         return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
569     }
570     if (y->IsBoolean()) {
571         JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
572         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
573         return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
574     }
575     if (y->IsNumber()) {
576         JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
577         return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
578     }
579     if (y->IsECMAObject()) {
580         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
581         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
582         return Equal(thread, x, yPrimitive);
583     }
584     return false;
585 }
586 
EqualHeapObject(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)587 bool JSTaggedValue::EqualHeapObject(JSThread *thread, const JSHandle<JSTaggedValue> &x,
588                                     const JSHandle<JSTaggedValue> &y)
589 {
590     if (y->IsHeapObject()) {
591         // if same type, must call Type::StrictEqual()
592         JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
593         JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
594         if (xType == yType) {
595             return StrictEqual(thread, x, y);
596         }
597     }
598     if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
599         if (x->IsECMAObject()) {
600             JSHandle<JSTaggedValue> xPrimitive(thread, ToPrimitive(thread, x));
601             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
602             return Equal(thread, xPrimitive, y);
603         }
604     }
605     return false;
606 }
607 
EqualNullOrUndefined(const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)608 bool JSTaggedValue::EqualNullOrUndefined(const JSHandle<JSTaggedValue> &x,
609                                          const JSHandle<JSTaggedValue> &y)
610 {
611     if (x->IsNull() && y->IsNull()) {
612         return true;
613     }
614     if (x->IsUndefined() && y->IsUndefined()) {
615         return true;
616     }
617     if (x->IsNull() && y->IsUndefined()) {
618         return true;
619     }
620     if (x->IsUndefined() && y->IsNull()) {
621         return true;
622     }
623     return false;
624 }
625 
626 static const uint32_t POWERS_OF_10[] = {
627     1,
628     10,
629     100,
630     1000,
631     10 * 1000,
632     100 * 1000,
633     1000 * 1000,
634     10 * 1000 * 1000,
635     100 * 1000 * 1000,
636     1000 * 1000 * 1000,
637 };
638 
IntLexicographicCompare(JSTaggedValue x,JSTaggedValue y)639 int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
640 {
641     ASSERT(x.IsInt() && y.IsInt());
642     int xValue = x.GetInt();
643     int yValue = y.GetInt();
644     if (xValue == yValue) {
645         return 0;
646     }
647     if (xValue == 0 || yValue == 0) {
648         return xValue > yValue ? 1 : -1;
649     }
650     uint32_t unsignedX = static_cast<uint32_t>(xValue);
651     uint32_t unsignedY = static_cast<uint32_t>(yValue);
652     if (yValue > 0) {
653         if (xValue < 0) {
654             return -1;
655         }
656     } else {
657         if (xValue > 0) {
658             return 1;
659         }
660         unsignedX = static_cast<uint32_t>(base::NegateWithWraparound(xValue));
661         unsignedY = static_cast<uint32_t>(base::NegateWithWraparound(yValue));
662     }
663     int xLog2 = 31 - __builtin_clz(unsignedX);
664     int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
665     xDigit -= unsignedX < POWERS_OF_10[xDigit];
666 
667     int yLog2 = 31 - __builtin_clz(unsignedY);
668     int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
669     yDigit -= unsignedY < POWERS_OF_10[yDigit];
670 
671     int res = 0;
672     if (xDigit > yDigit) {
673         // X has fewer digits.  We would like to simply scale up X but that
674         // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
675         // be scaled up to 9_000_000_000. So we scale up by the next
676         // smallest power and scale down Y to drop one digit. It is OK to
677         // drop one digit from the longer integer since the final digit is
678         // past the length of the shorter integer.
679         unsignedY *= POWERS_OF_10[xDigit - yDigit - 1];
680         unsignedX /= 10; // 10 : Decimal
681         res = 1;
682     }
683     if (yDigit > xDigit) {
684         unsignedX *= POWERS_OF_10[yDigit - xDigit - 1];
685         unsignedY /= 10; // 10 : Decimal
686         res = -1;
687     }
688     if (unsignedX > unsignedY) {
689         return 1;
690     }
691 
692     if (unsignedY > unsignedX) {
693         return -1;
694     }
695     return res;
696 }
697 
DoubleLexicographicCompare(JSTaggedValue x,JSTaggedValue y)698 int JSTaggedValue::DoubleLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
699 {
700     ASSERT(x.IsDouble() && y.IsDouble());
701     CString xStr = base::NumberHelper::DoubleToCString(x.GetDouble());
702     CString yStr = base::NumberHelper::DoubleToCString(y.GetDouble());
703     return xStr.compare(yStr);
704 }
705 
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)706 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
707                                         const JSHandle<JSTaggedValue> &y)
708 {
709     if (x->IsDate() && y->IsDate()) {
710         double timeX = JSDate::Cast(x->GetTaggedObject())->GetTimeValue(thread).GetDouble();
711         double timeY = JSDate::Cast(y->GetTaggedObject())->GetTimeValue(thread).GetDouble();
712         return StrictNumberCompare(timeX, timeY);
713     }
714     JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
715     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
716     JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
717     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
718     if (primX->IsString() && primY->IsString()) {
719         auto xHandle = JSHandle<EcmaString>(primX);
720         auto yHandle = JSHandle<EcmaString>(primY);
721         int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
722         if (result < 0) {
723             return ComparisonResult::LESS;
724         }
725         if (result == 0) {
726             return ComparisonResult::EQUAL;
727         }
728         return ComparisonResult::GREAT;
729     }
730     if (primX->IsBigInt()) {
731         if (primY->IsNumber()) {
732             JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
733             return BigInt::CompareWithNumber(bigint, primY);
734         } else if (primY->IsString()) {
735             JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
736             if (!bigY->IsBigInt()) {
737                 return ComparisonResult::UNDEFINED;
738             }
739             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
740         } else {
741             JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
742             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
743             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
744         }
745     }
746     if (primY->IsBigInt()) {
747         ComparisonResult res = Compare(thread, primY, primX);
748         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
749         if (res == ComparisonResult::GREAT) {
750             return ComparisonResult::LESS;
751         } else if (res == ComparisonResult::LESS) {
752             return ComparisonResult::GREAT;
753         }
754         return res;
755     }
756     double resultX = 0;
757     double resultY = 0;
758     if (primX->IsNumber()) {
759         resultX = primX->GetNumber();
760     } else {
761         JSTaggedNumber xNumber = ToNumber(thread, x);
762         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
763         resultX = xNumber.GetNumber();
764     }
765     if (primY->IsNumber()) {
766         resultY = primY->GetNumber();
767     } else {
768         JSTaggedNumber yNumber = ToNumber(thread, y);
769         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
770         resultY = yNumber.GetNumber();
771     }
772     return StrictNumberCompare(resultX, resultY);
773 }
774 
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)775 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
776 {
777     if (x.IsNumber() && y.IsNumber()) {
778         return true;
779     }
780     if (x.IsBoolean() && y.IsBoolean()) {
781         return true;
782     }
783     if (x.IsString() && y.IsString()) {
784         return true;
785     }
786     if (x.IsHeapObject() && y.IsHeapObject()) {
787         return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
788     }
789 
790     return false;
791 }
792 
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)793 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
794                                          PreferredPrimitiveType type)
795 {
796     if (tagged->IsECMAObject()) {
797         EcmaVM *vm = thread->GetEcmaVM();
798         JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
799 
800         JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
801         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
802         if (!exoticToprim->IsUndefined()) {
803             JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
804             JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
805             EcmaRuntimeCallInfo *info =
806                 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
807             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
808             info->SetCallArg(value);
809             JSTaggedValue valueResult = JSFunction::Call(info);
810             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
811             if (!valueResult.IsECMAObject()) {
812                 return valueResult;
813             }
814             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert object to primitive value",
815                 JSTaggedValue::Exception());
816         } else {
817             type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
818             return OrdinaryToPrimitive(thread, tagged, type);
819         }
820     }
821     return tagged.GetTaggedValue();
822 }
823 
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)824 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
825                                                  PreferredPrimitiveType type)
826 {
827     static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
828     ASSERT(tagged->IsECMAObject());
829     auto globalConst = thread->GlobalConstants();
830     for (uint8_t i = 0; i < 2; i++) {  // 2: 2 means value has 2 target types, string or value.
831         JSHandle<JSTaggedValue> keyString;
832         if ((static_cast<uint8_t>(type) ^ i) != 0) {
833             keyString = globalConst->GetHandledToStringString();
834         } else {
835             keyString = globalConst->GetHandledValueOfString();
836         }
837         JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
838         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
839         if (entryfunc->IsCallable()) {
840             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
841             EcmaRuntimeCallInfo *info =
842                 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
843             JSTaggedValue valueResult = JSFunction::Call(info);
844             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
845             if (!valueResult.IsECMAObject()) {
846                 return valueResult;
847             }
848         }
849     }
850     DumpExceptionObject(thread, tagged);
851     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
852 }
853 
ToString(JSThread * thread,JSTaggedValue val)854 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
855 {
856     JSHandle<JSTaggedValue> tagged(thread, val);
857     return ToString(thread, tagged);
858 }
859 
ExceptionToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)860 std::string JSTaggedValue::ExceptionToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
861 {
862     if (tagged->IsECMAObject()) {
863         return "Object";
864     }
865 
866     auto globalConst = thread->GlobalConstants();
867     JSHandle<EcmaString> value = JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
868     if (tagged->IsString()) {
869         value = JSHandle<EcmaString>(tagged);
870     } else if (tagged->IsSpecial()) {
871         switch (tagged->GetRawData()) {
872             case VALUE_UNDEFINED:
873                 value = JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
874                 break;
875             case VALUE_NULL:
876                 value = JSHandle<EcmaString>(globalConst->GetHandledNullString());
877                 break;
878             case VALUE_TRUE:
879                 value = JSHandle<EcmaString>(globalConst->GetHandledTrueString());
880                 break;
881             case VALUE_FALSE:
882                 value = JSHandle<EcmaString>(globalConst->GetHandledFalseString());
883                 break;
884             case VALUE_HOLE:
885                 break;
886             default:
887                 break;
888         }
889     } else if (tagged->IsNumber()) {
890         value = base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
891     } else if (tagged->IsBigInt()) {
892         JSHandle<BigInt> taggedValue(tagged);
893         value = BigInt::ToString(thread, taggedValue);
894     } else if (tagged->IsNativePointer()) {
895         value = NativePointerToString(thread, tagged);
896     }
897 
898     return EcmaStringAccessor(value).ToStdString(thread);
899 }
900 
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)901 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
902 {
903     if (tagged->IsString()) {
904         return JSHandle<EcmaString>(tagged);
905     }
906     auto globalConst = thread->GlobalConstants();
907     if (tagged->IsSpecial()) {
908         switch (tagged->GetRawData()) {
909             case VALUE_UNDEFINED: {
910                 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
911             }
912             case VALUE_NULL: {
913                 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
914             }
915             case VALUE_TRUE: {
916                 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
917             }
918             case VALUE_FALSE: {
919                 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
920             }
921             case VALUE_HOLE: {
922                 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
923             }
924             default:
925                 break;
926         }
927     }
928 
929     if (tagged->IsNumber()) {
930         return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
931     }
932 
933     if (tagged->IsBigInt()) {
934         JSHandle<BigInt> taggedValue(tagged);
935         return BigInt::ToString(thread, taggedValue);
936     }
937 
938     if (tagged->IsNativePointer()) {
939         return NativePointerToString(thread, tagged);
940     }
941 
942     auto emptyStr = globalConst->GetHandledEmptyString();
943     if (tagged->IsECMAObject()) {
944         JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
945         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
946         return ToString(thread, primValue);
947     }
948     DumpExceptionObject(thread, tagged);
949     // Already Include Symbol
950     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
951 }
952 
NativePointerToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)953 JSHandle<EcmaString> JSTaggedValue::NativePointerToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
954 {
955     JSHandle<JSNativePointer> taggedHandle(tagged);
956     std::stringstream stringstream;
957     stringstream << std::hex << taggedHandle->GetExternalPointer();
958     std::string nativePtrStr = "[External: " + stringstream.str() + "]";
959 
960     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
961     return factory->NewFromASCII(nativePtrStr);
962 }
963 
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)964 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
965 {
966     if (tagged->IsNumber()) {
967         return tagged.GetTaggedValue();
968     }
969 
970     if (tagged->IsString()) {
971         JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
972         if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), JSHandle<EcmaString>(tagged), str)) {
973             return JSTaggedValue(-0.0);
974         }
975         JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
976         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
977         if (SameValue(thread, ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
978             return tmp.GetTaggedValue();
979         }
980     }
981     return JSTaggedValue::Undefined();
982 }
983 
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)984 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
985 {
986     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
987     if (tagged->IsInt() || tagged->IsDouble()) {
988         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
989     }
990 
991     switch (tagged->GetRawData()) {
992         case JSTaggedValue::VALUE_UNDEFINED: {
993             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
994                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
995         }
996         case JSTaggedValue::VALUE_HOLE: {
997             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
998                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
999         }
1000         case JSTaggedValue::VALUE_NULL: {
1001             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
1002                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1003         }
1004         case JSTaggedValue::VALUE_TRUE:
1005         case JSTaggedValue::VALUE_FALSE: {
1006             return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
1007         }
1008         default: {
1009             break;
1010         }
1011     }
1012 
1013     if (tagged->IsECMAObject()) {
1014         return JSHandle<JSObject>::Cast(tagged);
1015     }
1016     if (tagged->IsSymbol()) {
1017         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
1018     }
1019     if (tagged->IsString()) {
1020         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
1021     }
1022     if (tagged->IsBigInt()) {
1023         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
1024     }
1025     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
1026                                 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
1027 }
1028 
1029 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)1030 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1031                                            const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
1032 {
1033     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1034         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString(thread);
1035         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString(thread);
1036         std::string message = "Cannot read property ";
1037         message.append(keyStr).append(" of ").append(objStr);
1038         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1039                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1040     }
1041     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1042 
1043     if (obj->IsJSProxy()) {
1044         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
1045     }
1046     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1047         return JSTypedArray::GetProperty(thread, obj, key);
1048     }
1049     if (obj->IsModuleNamespace()) {
1050         return ModuleNamespace::GetProperty(thread, obj, key);
1051     }
1052 
1053     if (obj->IsSpecialContainer()) {
1054         return GetJSAPIProperty(thread, obj, key);
1055     }
1056 
1057     return JSObject::GetProperty(thread, obj, key, sCheckMode);
1058 }
1059 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1060 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1061 {
1062     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1063         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString(thread);
1064         std::string message = "Cannot read property ";
1065         message.append(ToCString(key)).append(" of ").append(objStr);
1066         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1067                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1068     }
1069 
1070     if (obj->IsJSProxy()) {
1071         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1072         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1073     }
1074 
1075     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1076         return JSTypedArray::GetProperty(thread, obj, key);
1077     }
1078 
1079     if (obj->IsSpecialContainer()) {
1080         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1081         return GetJSAPIProperty(thread, obj, keyHandle);
1082     }
1083 
1084     return JSObject::GetProperty(thread, obj, key);
1085 }
1086 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)1087 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1088                                            const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1089 {
1090     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1091         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString(thread);
1092         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString(thread);
1093         std::string message = "Cannot read property ";
1094         message.append(keyStr).append(" of ").append(objStr);
1095         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1096                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1097     }
1098     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1099 
1100     if (obj->IsJSProxy()) {
1101         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
1102     }
1103     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1104         return JSTypedArray::GetProperty(thread, obj, key, receiver);
1105     }
1106 
1107     if (obj->IsSpecialContainer()) {
1108         return GetJSAPIProperty(thread, obj, key);
1109     }
1110 
1111     return JSObject::GetProperty(thread, obj, key, receiver);
1112 }
1113 
1114 // 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,SCheckMode checkMode)1115 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1116                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow,
1117                                 SCheckMode checkMode)
1118 {
1119     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1120         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1121     }
1122 
1123     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1124 
1125     // 4. Let success be O.[[Set]](P, V, O).
1126     bool success = false;
1127     if (obj->IsJSProxy()) {
1128         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
1129     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1130         success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
1131     } else if (obj->IsModuleNamespace()) {
1132         success = ModuleNamespace::SetProperty(thread, mayThrow);
1133     } else if (obj->IsSpecialContainer()) {
1134         success = SetJSAPIProperty(thread, obj, key, value);
1135     } else {
1136         success = JSObject::SetProperty(thread, obj, key, value, mayThrow, checkMode);
1137     }
1138     // 5. ReturnIfAbrupt(success).
1139     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1140     // 6. If success is false and Throw is true, throw a TypeError exception.
1141     // have done in JSObject::SetPropert.
1142     return success;
1143 }
1144 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)1145 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
1146                                 const JSHandle<JSTaggedValue> &value, bool mayThrow)
1147 {
1148     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1149         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1150     }
1151 
1152     // 4. Let success be O.[[Set]](P, V, O).
1153     bool success = false;
1154     if (obj->IsJSProxy()) {
1155         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1156         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
1157     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1158         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1159         success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
1160     } else if (obj->IsModuleNamespace()) {
1161         success = ModuleNamespace::SetProperty(thread, mayThrow);
1162     } else if (obj->IsSpecialContainer()) {
1163         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1164         success = SetJSAPIProperty(thread, obj, keyHandle, value);
1165     } else {
1166         success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
1167     }
1168     // 5. ReturnIfAbrupt(success).
1169     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1170     // 6. If success is false and Throw is true, throw a TypeError exception.
1171     // have done in JSObject::SetPropert.
1172     return success;
1173 }
1174 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)1175 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1176                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1177                                 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
1178 {
1179     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1180         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1181     }
1182 
1183     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1184 
1185     // 4. Let success be O.[[Set]](P, V, O).
1186     bool success = false;
1187     if (obj->IsJSProxy()) {
1188         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
1189     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1190         success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
1191     } else if (obj->IsModuleNamespace()) {
1192         success = ModuleNamespace::SetProperty(thread, mayThrow);
1193     } else if (obj->IsSpecialContainer()) {
1194         success = SetJSAPIProperty(thread, obj, key, value);
1195     } else {
1196         success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
1197     }
1198     // 5. ReturnIfAbrupt(success).
1199     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1200     // 6. If success is false and Throw is true, throw a TypeError exception.
1201     // have done in JSObject::SetPropert.
1202     return success;
1203 }
1204 
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)1205 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1206                                    const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
1207 {
1208     if (obj->IsJSProxy()) {
1209         return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
1210     }
1211 
1212     if (obj->IsModuleNamespace()) {
1213         return ModuleNamespace::DeleteProperty(thread, obj, key);
1214     }
1215 
1216     if (obj->IsTypedArray()) {
1217         return JSTypedArray::DeleteProperty(thread, obj, key);
1218     }
1219 
1220     if (obj->IsSpecialContainer()) {
1221         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
1222     }
1223 
1224     return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key, sCheckMode);
1225 }
1226 
1227 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1228 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1229                                           const JSHandle<JSTaggedValue> &key)
1230 {
1231     if (!obj->IsECMAObject()) {
1232         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
1233     }
1234     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1235 
1236     // 3. Let success be O.[[Delete]](P).
1237     bool success = DeleteProperty(thread, obj, key);
1238 
1239     // 4. ReturnIfAbrupt(success).
1240     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1241     // 5. If success is false, throw a TypeError exception
1242     if (!success) {
1243         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
1244     }
1245     return success;
1246 }
1247 
1248 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1249 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1250                                           const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1251 {
1252     // 1. Assert: Type(O) is Object.
1253     // 2. Assert: IsPropertyKey(P) is true.
1254     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1255     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1256     // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
1257     bool success = DefineOwnProperty(thread, obj, key, desc);
1258     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1259     // 4. If success is false, throw a TypeError exception.
1260     if (!success) {
1261         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot define property", false);
1262     }
1263     return success;
1264 }
1265 
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1266 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1267                                       const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1268                                       SCheckMode sCheckMode)
1269 {
1270     if (obj->IsJSArray()) {
1271         return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1272     }
1273 
1274     if (obj->IsJSSharedArray()) {
1275         return JSSharedArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc, sCheckMode);
1276     }
1277 
1278     if (obj->IsJSProxy()) {
1279         return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1280     }
1281 
1282     if (obj->IsTypedArray()) {
1283         return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
1284     }
1285 
1286     if (obj->IsModuleNamespace()) {
1287         return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
1288     }
1289 
1290     if (obj->IsSpecialContainer()) {
1291         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
1292     }
1293 
1294     return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1295 }
1296 
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1297 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1298                                    const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1299 {
1300     if (obj->IsJSProxy()) {
1301         return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1302     }
1303     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1304         return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
1305     }
1306     if (obj->IsModuleNamespace()) {
1307         return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
1308     }
1309     if (obj->IsSpecialContainer()) {
1310         return GetContainerProperty(thread, obj, key, desc);
1311     }
1312     return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1313 }
1314 
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto,bool isChangeProto)1315 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1316                                  const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
1317 {
1318     if (obj->IsJSShared() || proto->IsJSShared()) {
1319         THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetProtoWithSendable), false);
1320     }
1321 
1322     if (obj->IsJSProxy()) {
1323         return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
1324     }
1325     if (obj->IsModuleNamespace()) {
1326         return ModuleNamespace::SetPrototype(obj, proto);
1327     }
1328     if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
1329         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
1330     }
1331     if (obj->IsJSFunction() && proto->IsJSFunction()) {
1332         JSHandle<JSFunction> objFunc = JSHandle<JSFunction>::Cast(obj);
1333         JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass(thread));
1334         if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor(thread)) {
1335             JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
1336             objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype(thread));
1337         }
1338     }
1339 
1340     return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto, isChangeProto);
1341 }
1342 
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1343 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1344 {
1345     if (!obj->IsECMAObject()) {
1346         DumpExceptionObject(thread, obj);
1347         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
1348     }
1349     if (obj->IsJSProxy()) {
1350         return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
1351     }
1352     return JSObject::GetPrototype(thread, JSHandle<JSObject>(obj));
1353 }
1354 
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1355 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1356 {
1357     if (obj->IsJSProxy()) {
1358         return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
1359     }
1360     if (obj->IsModuleNamespace()) {
1361         return ModuleNamespace::PreventExtensions();
1362     }
1363     return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
1364 }
1365 
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1366 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1367 {
1368     if (obj->IsJSProxy()) {
1369         return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
1370     }
1371     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1372         return JSTypedArray::OwnPropertyKeys(thread, obj);
1373     }
1374     if (obj->IsSpecialContainer()) {
1375         return GetOwnContainerPropertyKeys(thread, obj);
1376     }
1377     if (obj->IsModuleNamespace()) {
1378         return ModuleNamespace::OwnPropertyKeys(thread, obj);
1379     }
1380     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1381 }
1382 
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)1383 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
1384                                                         const JSHandle<JSTaggedValue> &obj, uint32_t filter)
1385 {
1386     if (obj->IsJSProxy()) {
1387         return JSProxy::GetAllPropertyKeys(thread, JSHandle<JSProxy>(obj), filter);
1388     }
1389     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1390         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
1391         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1392     }
1393     if (obj->IsSpecialContainer()) {
1394         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
1395         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1396     }
1397     if (obj->IsModuleNamespace()) {
1398         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
1399         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1400     }
1401     return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
1402 }
1403 
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1404 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1405 {
1406     ASSERT(!obj->IsJSProxy());
1407     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1408         return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
1409     }
1410     if (obj->IsSpecialContainer()) {
1411         return GetOwnContainerEnumPropertyKeys(thread, obj);
1412     }
1413     if (obj->IsModuleNamespace()) {
1414         return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
1415     }
1416     return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1417 }
1418 
1419 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1420 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1421                                 const JSHandle<JSTaggedValue> &key)
1422 {
1423     if (obj->IsJSProxy()) {
1424         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
1425     }
1426     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1427         return JSTypedArray::HasProperty(thread, obj, key);
1428     }
1429     if (obj->IsModuleNamespace()) {
1430         return ModuleNamespace::HasProperty(thread, obj, key);
1431     }
1432     if (obj->IsSpecialContainer()) {
1433         return HasContainerProperty(thread, obj, key);
1434     }
1435     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1436 }
1437 
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1438 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1439 {
1440     if (obj->IsJSProxy()) {
1441         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1442         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1443     }
1444     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1445         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1446         return JSTypedArray::HasProperty(thread, obj, keyHandle);
1447     }
1448     if (obj->IsSpecialContainer()) {
1449         return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
1450     }
1451     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1452 }
1453 
1454 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1455 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1456                                    const JSHandle<JSTaggedValue> &key)
1457 {
1458     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1459 
1460     PropertyDescriptor desc(thread);
1461     return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
1462 }
1463 
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)1464 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1465 {
1466     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1467 
1468     PropertyDescriptor desc(thread);
1469     return JSObject::GlobalGetOwnProperty(thread, key, desc);
1470 }
1471 
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1472 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1473 {
1474     // 1. If v is an Object, return true.
1475     if (tagged->IsECMAObject()) {
1476         return true;
1477     }
1478     // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
1479     if (tagged->IsSymbol()) {
1480         JSTaggedValue symbolTable = thread->GetEcmaVM()->GetRegisterSymbols();
1481         auto *table = SymbolTable::Cast(symbolTable.GetTaggedObject());
1482         JSTaggedValue key = table->FindSymbol(thread, tagged.GetTaggedValue());
1483         if (key.IsUndefined()) {
1484             return true;
1485         }
1486     }
1487     // 3. Return false.
1488     return false;
1489 }
1490 
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1491 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1492 {
1493     if (tagged->IsInt() && tagged->GetInt() >= 0) {
1494         return JSTaggedNumber(tagged.GetTaggedValue());
1495     }
1496     if (tagged->IsUndefined()) {
1497         return JSTaggedNumber(0);
1498     }
1499     JSTaggedNumber integerIndex = ToNumber(thread, tagged);
1500     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
1501     if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
1502         return integerIndex;
1503     }
1504     double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
1505     if (len < 0.0 || len > SAFE_NUMBER) {
1506         THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
1507                                      JSTaggedNumber::Exception());
1508     }
1509     return JSTaggedNumber(len);
1510 }
1511 
1512 // 9.4.2.4 ArraySetLength 3 to 7
ToArrayLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,uint32_t * output)1513 bool JSTaggedValue::ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output)
1514 {
1515     // 3. Let newLen be ToUint32(Desc.[[Value]]).
1516     uint32_t newLen = ToUint32(thread, tagged);
1517     // 4. ReturnIfAbrupt(newLen).
1518     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1519 
1520     // 5. Let numberLen be ToNumber(Desc.[[Value]]).
1521     JSTaggedNumber numberLen = ToNumber(thread, tagged);
1522     // 6. ReturnIfAbrupt(newLen).
1523     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1524 
1525     // 7. If newLen != numberLen, throw a RangeError exception.
1526     if (JSTaggedNumber(newLen) != numberLen) {
1527         THROW_RANGE_ERROR_AND_RETURN(thread, "Not a valid array length", false);
1528     }
1529 
1530     *output = newLen;
1531     return true;
1532 }
1533 
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1534 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1535 {
1536 #if ENABLE_NEXT_OPTIMIZATION
1537     if (obj->IsECMAObject()) {
1538         return obj;
1539     }
1540 #endif
1541     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1542     if (obj->IsNumber()) {
1543         return JSHandle<JSTaggedValue>(thread,
1544                                        env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype(thread));
1545     }
1546     if (obj->IsBoolean()) {
1547         return JSHandle<JSTaggedValue>(thread,
1548                                        env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype(thread));
1549     }
1550     if (obj->IsString()) {
1551         return JSHandle<JSTaggedValue>(thread,
1552                                        env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype(thread));
1553     }
1554     if (obj->IsSymbol()) {
1555         return JSHandle<JSTaggedValue>(thread,
1556                                        env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype(thread));
1557     }
1558     if (obj->IsBigInt()) {
1559         return JSHandle<JSTaggedValue>(thread,
1560                                        env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype(thread));
1561     }
1562     return obj;
1563 }
1564 
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1565 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1566 {
1567     if (obj->IsUndefined()) {
1568         return JSTaggedValue::Undefined();
1569     }
1570 
1571     ASSERT(obj->IsECMAObject());
1572     return JSTaggedValue::GetPrototype(thread, obj);
1573 }
1574 
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1575 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1576                                          const JSHandle<JSTaggedValue> &key)
1577 {
1578     auto *hclass = obj->GetTaggedObject()->GetClass();
1579     JSType jsType = hclass->GetObjectType();
1580     switch (jsType) {
1581         case JSType::JS_API_ARRAY_LIST: {
1582             return JSHandle<JSAPIArrayList>::Cast(obj)->Has(thread, key.GetTaggedValue());
1583         }
1584         case JSType::JS_API_QUEUE: {
1585             return JSHandle<JSAPIQueue>::Cast(obj)->Has(thread, key.GetTaggedValue());
1586         }
1587         case JSType::JS_API_PLAIN_ARRAY: {
1588             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1589         }
1590         case JSType::JS_API_DEQUE: {
1591             return JSHandle<JSAPIDeque>::Cast(obj)->Has(thread, key.GetTaggedValue());
1592         }
1593         case JSType::JS_API_STACK: {
1594             return JSHandle<JSAPIStack>::Cast(obj)->Has(thread, key.GetTaggedValue());
1595         }
1596         case JSType::JS_API_LIST: {
1597             JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1598             return list->Has(thread, key.GetTaggedValue());
1599         }
1600         case JSType::JS_API_LINKED_LIST: {
1601             JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1602             return linkedList->Has(thread, key.GetTaggedValue());
1603         }
1604         case JSType::JS_API_HASH_MAP:
1605         case JSType::JS_API_HASH_SET:
1606         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1607         case JSType::JS_API_LIGHT_WEIGHT_SET:
1608         case JSType::JS_API_TREE_MAP:
1609         case JSType::JS_API_TREE_SET: {
1610             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1611         }
1612         case JSType::JS_API_VECTOR: {
1613             return JSHandle<JSAPIVector>::Cast(obj)->Has(thread, key.GetTaggedValue());
1614         }
1615         case JSType::JS_API_BITVECTOR: {
1616             return JSHandle<JSAPIBitVector>::Cast(obj)->Has(thread, key.GetTaggedValue());
1617         }
1618         default: {
1619             LOG_ECMA(FATAL) << "this branch is unreachable";
1620             UNREACHABLE();
1621         }
1622     }
1623     return false;
1624 }
1625 
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1626 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1627 {
1628     auto *hclass = obj->GetTaggedObject()->GetClass();
1629     JSType jsType = hclass->GetObjectType();
1630     switch (jsType) {
1631         case JSType::JS_API_ARRAY_LIST: {
1632             return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1633         }
1634         case JSType::JS_API_QUEUE: {
1635             return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1636         }
1637         case JSType::JS_API_PLAIN_ARRAY: {
1638             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1639         }
1640         case JSType::JS_API_DEQUE: {
1641             return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1642         }
1643         case JSType::JS_API_STACK: {
1644             return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1645         }
1646         case JSType::JS_API_LIST: {
1647             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1648         }
1649         case JSType::JS_API_LINKED_LIST: {
1650             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1651         }
1652         case JSType::JS_API_HASH_MAP:
1653         case JSType::JS_API_HASH_SET:
1654         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1655         case JSType::JS_API_LIGHT_WEIGHT_SET:
1656         case JSType::JS_API_TREE_MAP:
1657         case JSType::JS_API_TREE_SET: {
1658             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1659         }
1660         case JSType::JS_API_VECTOR: {
1661             return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1662         }
1663         case JSType::JS_API_BITVECTOR: {
1664             return JSAPIBitVector::OwnKeys(thread, JSHandle<JSAPIBitVector>::Cast(obj));
1665         }
1666         default: {
1667             LOG_ECMA(FATAL) << "this branch is unreachable";
1668             UNREACHABLE();
1669         }
1670     }
1671     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1672 }
1673 
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1674 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1675     const JSHandle<JSTaggedValue> &obj)
1676 {
1677     auto *hclass = obj->GetTaggedObject()->GetClass();
1678     JSType jsType = hclass->GetObjectType();
1679     switch (jsType) {
1680         case JSType::JS_API_QUEUE: {
1681             return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1682         }
1683         case JSType::JS_API_DEQUE: {
1684             return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1685         }
1686         case JSType::JS_API_LIST: {
1687             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1688         }
1689         case JSType::JS_API_LINKED_LIST: {
1690             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1691         }
1692         case JSType::JS_API_VECTOR:
1693         case JSType::JS_API_BITVECTOR:
1694         case JSType::JS_API_STACK:
1695         case JSType::JS_API_ARRAY_LIST:
1696         case JSType::JS_API_PLAIN_ARRAY:
1697         case JSType::JS_API_HASH_MAP:
1698         case JSType::JS_API_HASH_SET:
1699         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1700         case JSType::JS_API_LIGHT_WEIGHT_SET:
1701         case JSType::JS_API_TREE_MAP:
1702         case JSType::JS_API_TREE_SET: {
1703             return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1704         }
1705         default: {
1706             UNREACHABLE();
1707         }
1708     }
1709     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1710 }
1711 
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1712 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1713                                          const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1714 {
1715     if (key->IsInteger()) {
1716         auto *hclass = obj->GetTaggedObject()->GetClass();
1717         JSType jsType = hclass->GetObjectType();
1718         switch (jsType) {
1719             case JSType::JS_API_ARRAY_LIST: {
1720                 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1721             }
1722             case JSType::JS_API_QUEUE: {
1723                 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1724             }
1725             case JSType::JS_API_DEQUE: {
1726                 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1727             }
1728             case JSType::JS_API_STACK: {
1729                 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1730             }
1731             case JSType::JS_API_LIST: {
1732                 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1733             }
1734             case JSType::JS_API_LINKED_LIST: {
1735                 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1736             }
1737             case JSType::JS_API_PLAIN_ARRAY: {
1738                 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1739             }
1740             case JSType::JS_API_VECTOR: {
1741                 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1742             }
1743             case JSType::JS_API_BITVECTOR: {
1744                 return JSAPIBitVector::GetOwnProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1745             }
1746             default: {
1747                 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1748             }
1749         }
1750     } else {
1751         return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1752     }
1753     return false;
1754 }
1755 
StringToNumber(JSThread * thread,JSTaggedValue tagged)1756 JSTaggedNumber JSTaggedValue::StringToNumber(JSThread *thread, JSTaggedValue tagged)
1757 {
1758     EcmaStringAccessor strAccessor(tagged);
1759     size_t strLen = strAccessor.GetLength();
1760     if (strLen == 0) {
1761         return JSTaggedNumber(0);
1762     }
1763     if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
1764         common::IntegerCache *cache = nullptr;
1765 #if ENABLE_NEXT_OPTIMIZATION
1766         if ((strLen <= common::IntegerCache::MAX_INTEGER_CACHE_SIZE) && strAccessor.IsInternString()) {
1767             cache = common::IntegerCache::Extract(EcmaString::Cast(tagged)->ToBaseString());
1768             if (cache->IsInteger()) {
1769                 return JSTaggedNumber(cache->GetInteger());
1770             }
1771         }
1772 #endif
1773         Span<const uint8_t> str = strAccessor.FastToUtf8Span();
1774         if (strAccessor.GetLength() == 0) {
1775             return JSTaggedNumber(0);
1776         }
1777         auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), cache);
1778         if (isSuccess) {
1779             return result;
1780         }
1781     }
1782     CVector<uint8_t> buf;
1783     Span<const uint8_t> str = strAccessor.ToUtf8Span(thread, buf);
1784     double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
1785                                                   base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
1786     return JSTaggedNumber(d);
1787 }
1788 
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1789 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1790 {
1791     // 1. Let primValue be ? ToPrimitive(value, number)
1792     JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
1793     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1794     // 2. If Type(primValue) is BigInt, return primValue.
1795     if (primValue.IsBigInt()) {
1796         return JSHandle<JSTaggedValue>(thread, primValue);
1797     }
1798     // 3. Return ? ToNumber(primValue).
1799     JSTaggedNumber number = ToNumber(thread, primValue);
1800     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1801     JSHandle<JSTaggedValue> value(thread, number);
1802     return value;
1803 }
1804 
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1805 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1806                                                 const JSHandle<JSTaggedValue> &key)
1807 {
1808     if (key->IsInteger()) {
1809         auto *hclass = obj->GetTaggedObject()->GetClass();
1810         JSType jsType = hclass->GetObjectType();
1811         switch (jsType) {
1812             case JSType::JS_API_ARRAY_LIST: {
1813                 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1814             }
1815             case JSType::JS_API_LIST: {
1816                 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1817             }
1818             case JSType::JS_API_LINKED_LIST: {
1819                 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1820             }
1821             case JSType::JS_API_QUEUE: {
1822                 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1823             }
1824             case JSType::JS_API_DEQUE: {
1825                 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1826             }
1827             case JSType::JS_API_STACK: {
1828                 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1829             }
1830             case JSType::JS_API_PLAIN_ARRAY: {
1831                 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1832             }
1833             case JSType::JS_API_VECTOR: {
1834                 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1835             }
1836             case JSType::JS_API_BITVECTOR: {
1837                 return JSAPIBitVector::GetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1838             }
1839             case JSType::JS_API_FAST_BUFFER: {
1840                 return JSAPIFastBuffer::GetProperty(thread, JSHandle<JSAPIFastBuffer>::Cast(obj), key);
1841             }
1842             default: {
1843                 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1844             }
1845         }
1846     } else {
1847         return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1848     }
1849     return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1850 }
1851 
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1852 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1853                                      const JSHandle<JSTaggedValue> &key,
1854                                      const JSHandle<JSTaggedValue> &value)
1855 {
1856     if (key->IsInteger()) {
1857         auto *hclass = obj->GetTaggedObject()->GetClass();
1858         JSType jsType = hclass->GetObjectType();
1859         switch (jsType) {
1860             case JSType::JS_API_ARRAY_LIST: {
1861                 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1862             }
1863             case JSType::JS_API_LIST: {
1864                 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1865             }
1866             case JSType::JS_API_LINKED_LIST: {
1867                 JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1868                 return true;
1869             }
1870             case JSType::JS_API_QUEUE: {
1871                 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1872             }
1873             case JSType::JS_API_DEQUE: {
1874                 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1875             }
1876             case JSType::JS_API_STACK: {
1877                 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1878             }
1879             case JSType::JS_API_PLAIN_ARRAY: {
1880                 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1881             }
1882             case JSType::JS_API_VECTOR: {
1883                 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1884             }
1885             case JSType::JS_API_BITVECTOR: {
1886                 return JSAPIBitVector::SetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key, value);
1887             }
1888             case JSType::JS_API_FAST_BUFFER: {
1889                 return JSAPIFastBuffer::SetProperty(thread, JSHandle<JSAPIFastBuffer>::Cast(obj), key, value);
1890             }
1891             default: {
1892                 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1893             }
1894         }
1895     } else {
1896         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1897     }
1898     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1899 }
1900 
DumpExceptionObject(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1901 void JSTaggedValue::DumpExceptionObject(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1902 {
1903     if (thread->GetEcmaVM()->GetJSOptions().EnableExceptionBacktrace()) {
1904         DesensitizedDump(thread, obj);
1905     }
1906 }
1907 
DesensitizedDump(const JSThread * thread,const JSHandle<JSTaggedValue> & obj)1908 void JSTaggedValue::DesensitizedDump(const JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1909 {
1910     std::ostringstream oss;
1911     obj->Dump(thread, oss, true);
1912     std::regex reg("0x[0-9a-fA-F]+");
1913     std::string sensitiveStr = std::regex_replace(oss.str(), reg, "");
1914     LOG_ECMA(ERROR) << "DumpExceptionObject: " << sensitiveStr;
1915 }
1916 
PublishSharedValueSlow(JSThread * thread,JSHandle<JSTaggedValue> value)1917 JSHandle<JSTaggedValue> JSTaggedValue::PublishSharedValueSlow(JSThread *thread, JSHandle<JSTaggedValue> value)
1918 {
1919     SharedValuePublishGuard guard;
1920 
1921     ASSERT(value->IsTreeString());
1922     EcmaString *flatStr = EcmaStringAccessor::Flatten(thread->GetEcmaVM(), JSHandle<EcmaString>(value));
1923     return JSHandle<JSTaggedValue>(thread, JSTaggedValue(flatStr));
1924 }
1925 
GetStringKeyHashCode(const JSThread * thread) const1926 uint32_t JSTaggedValue::GetStringKeyHashCode(const JSThread *thread) const
1927 {
1928     ASSERT(IsString());
1929     return EcmaStringAccessor(GetTaggedObject()).GetHashcode(thread);
1930 }
1931 }  // namespace panda::ecmascript
1932