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