• 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     DISALLOW_GARBAGE_COLLECTION;
85     if (tagged.IsInt() || tagged.IsDouble()) {
86         return JSTaggedNumber(tagged);
87     }
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 
106     if (tagged.IsString()) {
107         return StringToNumber(tagged);
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->IsStableArrayElementsGuardiansInvalid();
357 }
358 
IsStableJSArguments(JSThread * thread) const359 bool JSTaggedValue::IsStableJSArguments(JSThread *thread) const
360 {
361     return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArguments() &&
362            !thread->IsStableArrayElementsGuardiansInvalid();
363 }
364 
IsTaggedArray() const365 bool JSTaggedValue::IsTaggedArray() const
366 {
367     return IsHeapObject() && GetTaggedObject()->GetClass()->IsTaggedArray();
368 }
369 
IsJSProxy() const370 bool JSTaggedValue::IsJSProxy() const
371 {
372     return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxy();
373 }
374 
IsGeneratorObject() const375 bool JSTaggedValue::IsGeneratorObject() const
376 {
377     return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject();
378 }
379 
IsGeneratorContext() const380 bool JSTaggedValue::IsGeneratorContext() const
381 {
382     return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext();
383 }
384 
HasStableElements(JSThread * thread) const385 bool JSTaggedValue::HasStableElements(JSThread *thread) const
386 {
387     return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableElements() &&
388            !thread->IsStableArrayElementsGuardiansInvalid();
389 }
390 
WithinInt32() const391 bool JSTaggedValue::WithinInt32() const
392 {
393     if (!IsNumber()) {
394         return false;
395     }
396 
397     double doubleValue = GetNumber();
398     if (base::bit_cast<int64_t>(doubleValue) == base::bit_cast<int64_t>(-0.0)) {
399         return false;
400     }
401 
402     int32_t intvalue = base::NumberHelper::DoubleToInt(doubleValue, base::INT32_BITS);
403     return doubleValue == static_cast<double>(intvalue);
404 }
405 
IsZero() const406 bool JSTaggedValue::IsZero() const
407 {
408     if (GetRawData() == VALUE_ZERO) {
409         return true;
410     }
411     if (IsDouble()) {
412         const double limit = 1e-8;
413         return (std::abs(GetDouble() - 0.0) <= limit);
414     }
415     return false;
416 }
417 
Equal(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)418 bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
419 {
420     if (x->IsNumber()) {
421         return EqualNumber(thread, x, y);
422     }
423 
424     if (x->IsString()) {
425         return EqualString(thread, x, y);
426     }
427 
428     if (x->IsBoolean()) {
429         JSTaggedNumber xNumber = ToNumber(thread, x);
430         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
431         return Equal(thread, JSHandle<JSTaggedValue>(thread, xNumber), y);
432     }
433 
434     if (x->IsSymbol()) {
435         return EqualSymbol(thread, x, y);
436     }
437 
438     if (x->IsBigInt()) {
439         return EqualBigInt(thread, x, y);
440     }
441 
442     if (x->IsHeapObject()) {
443         return EqualHeapObject(thread, x, y);
444     }
445 
446     return EqualNullOrUndefined(x, y);
447 }
448 
EqualNumber(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)449 bool JSTaggedValue::EqualNumber(JSThread *thread, const JSHandle<JSTaggedValue> &x,
450                                 const JSHandle<JSTaggedValue> &y)
451 {
452     if (y->IsNumber()) {
453         return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
454     }
455     if (y->IsString()) {
456             JSTaggedNumber yNumber = ToNumber(thread, y);
457             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
458             return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
459     }
460     if (y->IsBoolean()) {
461         JSTaggedNumber yNumber = ToNumber(thread, y);
462         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
463         return StrictNumberEquals(x->ExtractNumber(), yNumber.GetNumber());
464     }
465     if (y->IsBigInt()) {
466         return Equal(thread, y, x);
467     }
468     if (y->IsHeapObject() && !y->IsSymbol()) {
469         if (!(y->IsECMAObject())) {
470             return false;
471         }
472         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
473         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
474         return Equal(thread, x, yPrimitive);
475     }
476     return false;
477 }
478 
EqualString(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)479 bool JSTaggedValue::EqualString(JSThread *thread, const JSHandle<JSTaggedValue> &x,
480                                 const JSHandle<JSTaggedValue> &y)
481 {
482     if (y->IsString()) {
483         return EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(),
484                                                    JSHandle<EcmaString>(x),
485                                                    JSHandle<EcmaString>(y));
486     }
487     if (y->IsNumber()) {
488         JSTaggedNumber xNumber = ToNumber(thread, x);
489         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
490         return StrictNumberEquals(xNumber.GetNumber(), y->ExtractNumber());
491     }
492     if (y->IsBoolean()) {
493         JSTaggedNumber xNumber = ToNumber(thread, x);
494         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
495         JSTaggedNumber yNumber = ToNumber(thread, y);
496         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
497         return StrictNumberEquals(xNumber.GetNumber(), yNumber.GetNumber());
498     }
499     if (y->IsBigInt()) {
500         return Equal(thread, y, x);
501     }
502     if (y->IsHeapObject() && !y->IsSymbol()) {
503         if (!(y->IsECMAObject())) {
504             return false;
505         }
506         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
507         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
508         return Equal(thread, x, yPrimitive);
509     }
510     return false;
511 }
512 
EqualSymbol(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)513 bool JSTaggedValue::EqualSymbol(JSThread *thread, const JSHandle<JSTaggedValue> &x,
514                                 const JSHandle<JSTaggedValue> &y)
515 {
516     if (y->IsSymbol()) {
517         return x.GetTaggedValue() == y.GetTaggedValue();
518     }
519     if (y->IsBigInt() || y->IsString()) {
520         return false;
521     }
522     if (y->IsHeapObject()) {
523         if (!(y->IsECMAObject())) {
524             return false;
525         }
526         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
527         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
528         return Equal(thread, x, yPrimitive);
529     }
530     return false;
531 }
532 
EqualBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)533 bool JSTaggedValue::EqualBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &x,
534                                 const JSHandle<JSTaggedValue> &y)
535 {
536     if (y->IsBigInt()) {
537         return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
538     }
539     if (y->IsString()) {
540         JSHandle<JSTaggedValue> yNumber(thread, base::NumberHelper::StringToBigInt(thread, y));
541         if (!yNumber->IsBigInt()) {
542             return false;
543         }
544         return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
545     }
546     if (y->IsBoolean()) {
547         JSHandle<JSTaggedValue> yNumber(thread, ToBigInt(thread, y));
548         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
549         return BigInt::Equal(x.GetTaggedValue(), yNumber.GetTaggedValue());
550     }
551     if (y->IsNumber()) {
552         JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(x);
553         return BigInt::CompareWithNumber(bigint, y) == ComparisonResult::EQUAL;
554     }
555     if (y->IsHeapObject() && !y->IsSymbol()) {
556         if (!(y->IsECMAObject())) {
557             return false;
558         }
559         JSHandle<JSTaggedValue> yPrimitive(thread, ToPrimitive(thread, y));
560         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
561         return Equal(thread, x, yPrimitive);
562     }
563     return false;
564 }
565 
EqualHeapObject(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)566 bool JSTaggedValue::EqualHeapObject(JSThread *thread, const JSHandle<JSTaggedValue> &x,
567                                     const JSHandle<JSTaggedValue> &y)
568 {
569     if (y->IsHeapObject()) {
570         // if same type, must call Type::StrictEqual()
571         JSType xType = x.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
572         JSType yType = y.GetTaggedValue().GetTaggedObject()->GetClass()->GetObjectType();
573         if (xType == yType) {
574             return StrictEqual(thread, x, y);
575         }
576     }
577     if (y->IsNumber() || y->IsStringOrSymbol() || y->IsBoolean() || y->IsBigInt()) {
578         if (!(x->IsECMAObject())) {
579             return false;
580         }
581         JSHandle<JSTaggedValue> xPrimitive(thread, ToPrimitive(thread, x));
582         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
583         return Equal(thread, xPrimitive, y);
584     }
585     return false;
586 }
587 
EqualNullOrUndefined(const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)588 bool JSTaggedValue::EqualNullOrUndefined(const JSHandle<JSTaggedValue> &x,
589                                          const JSHandle<JSTaggedValue> &y)
590 {
591     if (x->IsNull() && y->IsNull()) {
592         return true;
593     }
594     if (x->IsUndefined() && y->IsUndefined()) {
595         return true;
596     }
597     if (x->IsNull() && y->IsUndefined()) {
598         return true;
599     }
600     if (x->IsUndefined() && y->IsNull()) {
601         return true;
602     }
603     return false;
604 }
605 
606 static const uint32_t POWERS_OF_10[] = {
607     1,
608     10,
609     100,
610     1000,
611     10 * 1000,
612     100 * 1000,
613     1000 * 1000,
614     10 * 1000 * 1000,
615     100 * 1000 * 1000,
616     1000 * 1000 * 1000,
617 };
618 
IntLexicographicCompare(JSTaggedValue x,JSTaggedValue y)619 int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
620 {
621     ASSERT(x.IsInt() && y.IsInt());
622     int xValue = x.GetInt();
623     int yValue = y.GetInt();
624     if (xValue == yValue) {
625         return 0;
626     }
627     if (xValue == 0 || yValue == 0) {
628         return xValue > yValue ? 1 : -1;
629     }
630     uint32_t unsignedX = static_cast<uint32_t>(xValue);
631     uint32_t unsignedY = static_cast<uint32_t>(yValue);
632     if (yValue > 0) {
633         if (xValue < 0) {
634             return -1;
635         }
636     } else {
637         if (xValue > 0) {
638             return 1;
639         }
640         unsignedX = static_cast<uint32_t>(base::NegateWithWraparound(xValue));
641         unsignedY = static_cast<uint32_t>(base::NegateWithWraparound(yValue));
642     }
643     int xLog2 = 31 - __builtin_clz(unsignedX);
644     int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
645     xDigit -= unsignedX < POWERS_OF_10[xDigit];
646 
647     int yLog2 = 31 - __builtin_clz(unsignedY);
648     int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
649     yDigit -= unsignedY < POWERS_OF_10[yDigit];
650 
651     int res = 0;
652     if (xDigit > yDigit) {
653         // X has fewer digits.  We would like to simply scale up X but that
654         // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
655         // be scaled up to 9_000_000_000. So we scale up by the next
656         // smallest power and scale down Y to drop one digit. It is OK to
657         // drop one digit from the longer integer since the final digit is
658         // past the length of the shorter integer.
659         unsignedY *= POWERS_OF_10[xDigit - yDigit - 1];
660         unsignedX /= 10; // 10 : Decimal
661         res = 1;
662     }
663     if (yDigit > xDigit) {
664         unsignedX *= POWERS_OF_10[yDigit - xDigit - 1];
665         unsignedY /= 10; // 10 : Decimal
666         res = -1;
667     }
668     if (unsignedX > unsignedY) {
669         return 1;
670     }
671 
672     if (unsignedY > unsignedX) {
673         return -1;
674     }
675     return res;
676 }
677 
Compare(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)678 ComparisonResult JSTaggedValue::Compare(JSThread *thread, const JSHandle<JSTaggedValue> &x,
679                                         const JSHandle<JSTaggedValue> &y)
680 {
681     if (x->IsDate() && y->IsDate()) {
682         double timeX = JSDate::Cast(x->GetTaggedObject())->GetTimeValue().GetDouble();
683         double timeY = JSDate::Cast(y->GetTaggedObject())->GetTimeValue().GetDouble();
684         return StrictNumberCompare(timeX, timeY);
685     }
686     JSHandle<JSTaggedValue> primX(thread, ToPrimitive(thread, x));
687     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
688     JSHandle<JSTaggedValue> primY(thread, ToPrimitive(thread, y));
689     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
690     if (primX->IsString() && primY->IsString()) {
691         auto xHandle = JSHandle<EcmaString>(primX);
692         auto yHandle = JSHandle<EcmaString>(primY);
693         int result = EcmaStringAccessor::Compare(thread->GetEcmaVM(), xHandle, yHandle);
694         if (result < 0) {
695             return ComparisonResult::LESS;
696         }
697         if (result == 0) {
698             return ComparisonResult::EQUAL;
699         }
700         return ComparisonResult::GREAT;
701     }
702     if (primX->IsBigInt()) {
703         if (primY->IsNumber()) {
704             JSHandle<BigInt> bigint = JSHandle<BigInt>::Cast(primX);
705             return BigInt::CompareWithNumber(bigint, primY);
706         } else if (primY->IsString()) {
707             JSHandle<JSTaggedValue> bigY(thread, base::NumberHelper::StringToBigInt(thread, primY));
708             if (!bigY->IsBigInt()) {
709                 return ComparisonResult::UNDEFINED;
710             }
711             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
712         } else {
713             JSHandle<JSTaggedValue> bigY(thread, ToBigInt(thread, primY));
714             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
715             return BigInt::Compare(primX.GetTaggedValue(), bigY.GetTaggedValue());
716         }
717     }
718     if (primY->IsBigInt()) {
719         ComparisonResult res = Compare(thread, primY, primX);
720         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
721         if (res == ComparisonResult::GREAT) {
722             return ComparisonResult::LESS;
723         } else if (res == ComparisonResult::LESS) {
724             return ComparisonResult::GREAT;
725         }
726         return res;
727     }
728     double resultX = 0;
729     double resultY = 0;
730     if (primX->IsNumber()) {
731         resultX = primX->GetNumber();
732     } else {
733         JSTaggedNumber xNumber = ToNumber(thread, x);
734         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
735         resultX = xNumber.GetNumber();
736     }
737     if (primY->IsNumber()) {
738         resultY = primY->GetNumber();
739     } else {
740         JSTaggedNumber yNumber = ToNumber(thread, y);
741         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
742         resultY = yNumber.GetNumber();
743     }
744     return StrictNumberCompare(resultX, resultY);
745 }
746 
IsSameTypeOrHClass(JSTaggedValue x,JSTaggedValue y)747 bool JSTaggedValue::IsSameTypeOrHClass(JSTaggedValue x, JSTaggedValue y)
748 {
749     if (x.IsNumber() && y.IsNumber()) {
750         return true;
751     }
752     if (x.IsBoolean() && y.IsBoolean()) {
753         return true;
754     }
755     if (x.IsString() && y.IsString()) {
756         return true;
757     }
758     if (x.IsHeapObject() && y.IsHeapObject()) {
759         return x.GetTaggedObject()->GetClass() == y.GetTaggedObject()->GetClass();
760     }
761 
762     return false;
763 }
764 
ToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)765 JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
766                                          PreferredPrimitiveType type)
767 {
768     if (tagged->IsECMAObject()) {
769         EcmaVM *vm = thread->GetEcmaVM();
770         JSHandle<JSTaggedValue> keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
771 
772         JSHandle<JSTaggedValue> exoticToprim = JSObject::GetMethod(thread, tagged, keyString);
773         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
774         if (!exoticToprim->IsUndefined()) {
775             JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
776             JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
777             EcmaRuntimeCallInfo *info =
778                 EcmaInterpreter::NewRuntimeCallInfo(thread, exoticToprim, tagged, undefined, 1);
779             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
780             info->SetCallArg(value);
781             JSTaggedValue valueResult = JSFunction::Call(info);
782             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
783             if (!valueResult.IsECMAObject()) {
784                 return valueResult;
785             }
786             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert object to primitive value",
787                 JSTaggedValue::Exception());
788         } else {
789             type = (type == NO_PREFERENCE) ? PREFER_NUMBER : type;
790             return OrdinaryToPrimitive(thread, tagged, type);
791         }
792     }
793     return tagged.GetTaggedValue();
794 }
795 
OrdinaryToPrimitive(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,PreferredPrimitiveType type)796 JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandle<JSTaggedValue> &tagged,
797                                                  PreferredPrimitiveType type)
798 {
799     static_assert(PREFER_NUMBER == 0 && PREFER_STRING == 1);
800     ASSERT(tagged->IsECMAObject());
801     auto globalConst = thread->GlobalConstants();
802     for (uint8_t i = 0; i < 2; i++) {  // 2: 2 means value has 2 target types, string or value.
803         JSHandle<JSTaggedValue> keyString;
804         if ((static_cast<uint8_t>(type) ^ i) != 0) {
805             keyString = globalConst->GetHandledToStringString();
806         } else {
807             keyString = globalConst->GetHandledValueOfString();
808         }
809         JSHandle<JSTaggedValue> entryfunc = GetProperty(thread, tagged, keyString).GetValue();
810         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
811         if (entryfunc->IsCallable()) {
812             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
813             EcmaRuntimeCallInfo *info =
814                 EcmaInterpreter::NewRuntimeCallInfo(thread, entryfunc, tagged, undefined, 0);
815             JSTaggedValue valueResult = JSFunction::Call(info);
816             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
817             if (!valueResult.IsECMAObject()) {
818                 return valueResult;
819             }
820         }
821     }
822     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a Primitive", JSTaggedValue::Undefined());
823 }
824 
ToString(JSThread * thread,JSTaggedValue val)825 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, JSTaggedValue val)
826 {
827     JSHandle<JSTaggedValue> tagged(thread, val);
828     return ToString(thread, tagged);
829 }
830 
ToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)831 JSHandle<EcmaString> JSTaggedValue::ToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
832 {
833     if (tagged->IsString()) {
834         return JSHandle<EcmaString>(tagged);
835     }
836     auto globalConst = thread->GlobalConstants();
837     if (tagged->IsSpecial()) {
838         switch (tagged->GetRawData()) {
839             case VALUE_UNDEFINED: {
840                 return JSHandle<EcmaString>(globalConst->GetHandledUndefinedString());
841             }
842             case VALUE_NULL: {
843                 return JSHandle<EcmaString>(globalConst->GetHandledNullString());
844             }
845             case VALUE_TRUE: {
846                 return JSHandle<EcmaString>(globalConst->GetHandledTrueString());
847             }
848             case VALUE_FALSE: {
849                 return JSHandle<EcmaString>(globalConst->GetHandledFalseString());
850             }
851             case VALUE_HOLE: {
852                 return JSHandle<EcmaString>(globalConst->GetHandledEmptyString());
853             }
854             default:
855                 break;
856         }
857     }
858 
859     if (tagged->IsNumber()) {
860         return base::NumberHelper::NumberToString(thread, tagged.GetTaggedValue());
861     }
862 
863     if (tagged->IsBigInt()) {
864         JSHandle<BigInt> taggedValue(tagged);
865         return BigInt::ToString(thread, taggedValue);
866     }
867 
868     if (tagged->IsNativePointer()) {
869         return NativePointerToString(thread, tagged);
870     }
871 
872     auto emptyStr = globalConst->GetHandledEmptyString();
873     if (tagged->IsECMAObject()) {
874         JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_STRING));
875         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<EcmaString>(emptyStr));
876         return ToString(thread, primValue);
877     }
878     // Already Include Symbol
879     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a illegal value to a String", JSHandle<EcmaString>(emptyStr));
880 }
881 
NativePointerToString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)882 JSHandle<EcmaString> JSTaggedValue::NativePointerToString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
883 {
884     JSHandle<JSNativePointer> taggedHandle(tagged);
885     std::stringstream stringstream;
886     stringstream << std::hex << taggedHandle->GetExternalPointer();
887     std::string nativePtrStr = "[External: " + stringstream.str() + "]";
888 
889     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
890     return factory->NewFromASCII(nativePtrStr);
891 }
892 
CanonicalNumericIndexString(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)893 JSTaggedValue JSTaggedValue::CanonicalNumericIndexString(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
894 {
895     if (tagged->IsNumber()) {
896         return tagged.GetTaggedValue();
897     }
898 
899     if (tagged->IsString()) {
900         JSHandle<EcmaString> str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("-0");
901         if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), JSHandle<EcmaString>(tagged), str)) {
902             return JSTaggedValue(-0.0);
903         }
904         JSHandle<JSTaggedValue> tmp(thread, ToNumber(thread, tagged));
905         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
906         if (SameValue(ToString(thread, tmp).GetTaggedValue(), tagged.GetTaggedValue())) {
907             return tmp.GetTaggedValue();
908         }
909     }
910     return JSTaggedValue::Undefined();
911 }
912 
ToObject(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)913 JSHandle<JSObject> JSTaggedValue::ToObject(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
914 {
915     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
916     if (tagged->IsInt() || tagged->IsDouble()) {
917         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_NUMBER, tagged));
918     }
919 
920     switch (tagged->GetRawData()) {
921         case JSTaggedValue::VALUE_UNDEFINED: {
922             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a UNDEFINED value to a JSObject",
923                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
924         }
925         case JSTaggedValue::VALUE_HOLE: {
926             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a HOLE value to a JSObject",
927                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
928         }
929         case JSTaggedValue::VALUE_NULL: {
930             THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a NULL value to a JSObject",
931                                         JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
932         }
933         case JSTaggedValue::VALUE_TRUE:
934         case JSTaggedValue::VALUE_FALSE: {
935             return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BOOLEAN, tagged));
936         }
937         default: {
938             break;
939         }
940     }
941 
942     if (tagged->IsECMAObject()) {
943         return JSHandle<JSObject>::Cast(tagged);
944     }
945     if (tagged->IsSymbol()) {
946         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_SYMBOL, tagged));
947     }
948     if (tagged->IsString()) {
949         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_STRING, tagged));
950     }
951     if (tagged->IsBigInt()) {
952         return JSHandle<JSObject>::Cast(factory->NewJSPrimitiveRef(PrimitiveType::PRIMITIVE_BIGINT, tagged));
953     }
954     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown object value to a JSObject",
955                                 JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
956 }
957 
958 // 7.3.1 Get ( O, P )
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,SCheckMode sCheckMode)959 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
960                                            const JSHandle<JSTaggedValue> &key, SCheckMode sCheckMode)
961 {
962     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
963         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
964         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
965         std::string message = "Cannot read property ";
966         message.append(keyStr).append(" of ").append(objStr);
967         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
968                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
969     }
970     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
971 
972     if (obj->IsJSProxy()) {
973         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key);
974     }
975     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
976         return JSTypedArray::GetProperty(thread, obj, key);
977     }
978     if (obj->IsModuleNamespace()) {
979         return ModuleNamespace::GetProperty(thread, obj, key);
980     }
981 
982     if (obj->IsSpecialContainer()) {
983         return GetJSAPIProperty(thread, obj, key);
984     }
985 
986     return JSObject::GetProperty(thread, obj, key, sCheckMode);
987 }
988 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)989 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
990 {
991     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
992         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
993         std::string message = "Cannot read property ";
994         message.append(ToCString(key)).append(" of ").append(objStr);
995         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
996                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
997     }
998 
999     if (obj->IsJSProxy()) {
1000         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1001         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1002     }
1003 
1004     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1005         return JSTypedArray::GetProperty(thread, obj, key);
1006     }
1007 
1008     if (obj->IsSpecialContainer()) {
1009         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1010         return GetJSAPIProperty(thread, obj, keyHandle);
1011     }
1012 
1013     return JSObject::GetProperty(thread, obj, key);
1014 }
1015 
GetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & receiver)1016 OperationResult JSTaggedValue::GetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1017                                            const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &receiver)
1018 {
1019     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1020         std::string keyStr = EcmaStringAccessor(ToString(thread, key)).ToStdString();
1021         std::string objStr = EcmaStringAccessor(ToString(thread, obj)).ToStdString();
1022         std::string message = "Cannot read property ";
1023         message.append(keyStr).append(" of ").append(objStr);
1024         THROW_TYPE_ERROR_AND_RETURN(thread, message.c_str(),
1025                                     OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
1026     }
1027     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1028 
1029     if (obj->IsJSProxy()) {
1030         return JSProxy::GetProperty(thread, JSHandle<JSProxy>(obj), key, receiver);
1031     }
1032     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1033         return JSTypedArray::GetProperty(thread, obj, key, receiver);
1034     }
1035 
1036     if (obj->IsSpecialContainer()) {
1037         return GetJSAPIProperty(thread, obj, key);
1038     }
1039 
1040     return JSObject::GetProperty(thread, obj, key, receiver);
1041 }
1042 
1043 // 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)1044 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1045                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value, bool mayThrow,
1046                                 SCheckMode checkMode)
1047 {
1048     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1049         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1050     }
1051 
1052     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1053 
1054     // 4. Let success be O.[[Set]](P, V, O).
1055     bool success = false;
1056     if (obj->IsJSProxy()) {
1057         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, mayThrow);
1058     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1059         success = JSTypedArray::SetProperty(thread, obj, key, value, mayThrow);
1060     } else if (obj->IsModuleNamespace()) {
1061         success = ModuleNamespace::SetProperty(thread, mayThrow);
1062     } else if (obj->IsSpecialContainer()) {
1063         success = SetJSAPIProperty(thread, obj, key, value);
1064     } else {
1065         success = JSObject::SetProperty(thread, obj, key, value, mayThrow, checkMode);
1066     }
1067     // 5. ReturnIfAbrupt(success).
1068     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1069     // 6. If success is false and Throw is true, throw a TypeError exception.
1070     // have done in JSObject::SetPropert.
1071     return success;
1072 }
1073 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key,const JSHandle<JSTaggedValue> & value,bool mayThrow)1074 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key,
1075                                 const JSHandle<JSTaggedValue> &value, bool mayThrow)
1076 {
1077     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1078         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1079     }
1080 
1081     // 4. Let success be O.[[Set]](P, V, O).
1082     bool success = false;
1083     if (obj->IsJSProxy()) {
1084         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1085         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), keyHandle, value, mayThrow);
1086     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1087         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1088         success = JSTypedArray::SetProperty(thread, obj, keyHandle, value, mayThrow);
1089     } else if (obj->IsModuleNamespace()) {
1090         success = ModuleNamespace::SetProperty(thread, mayThrow);
1091     } else if (obj->IsSpecialContainer()) {
1092         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1093         success = SetJSAPIProperty(thread, obj, keyHandle, value);
1094     } else {
1095         success = JSObject::SetProperty(thread, obj, key, value, mayThrow);
1096     }
1097     // 5. ReturnIfAbrupt(success).
1098     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1099     // 6. If success is false and Throw is true, throw a TypeError exception.
1100     // have done in JSObject::SetPropert.
1101     return success;
1102 }
1103 
SetProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value,const JSHandle<JSTaggedValue> & receiver,bool mayThrow)1104 bool JSTaggedValue::SetProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1105                                 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
1106                                 const JSHandle<JSTaggedValue> &receiver, bool mayThrow)
1107 {
1108     if (obj->IsUndefined() || obj->IsNull() || obj->IsHole()) {
1109         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a Valid object", false);
1110     }
1111 
1112     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1113 
1114     // 4. Let success be O.[[Set]](P, V, O).
1115     bool success = false;
1116     if (obj->IsJSProxy()) {
1117         success = JSProxy::SetProperty(thread, JSHandle<JSProxy>(obj), key, value, receiver, mayThrow);
1118     } else if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1119         success = JSTypedArray::SetProperty(thread, obj, key, value, receiver, mayThrow);
1120     } else if (obj->IsModuleNamespace()) {
1121         success = ModuleNamespace::SetProperty(thread, mayThrow);
1122     } else if (obj->IsSpecialContainer()) {
1123         success = SetJSAPIProperty(thread, obj, key, value);
1124     } else {
1125         success = JSObject::SetProperty(thread, obj, key, value, receiver, mayThrow);
1126     }
1127     // 5. ReturnIfAbrupt(success).
1128     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1129     // 6. If success is false and Throw is true, throw a TypeError exception.
1130     // have done in JSObject::SetPropert.
1131     return success;
1132 }
1133 
DeleteProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1134 bool JSTaggedValue::DeleteProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1135                                    const JSHandle<JSTaggedValue> &key)
1136 {
1137     if (obj->IsJSProxy()) {
1138         return JSProxy::DeleteProperty(thread, JSHandle<JSProxy>(obj), key);
1139     }
1140 
1141     if (obj->IsModuleNamespace()) {
1142         return ModuleNamespace::DeleteProperty(thread, obj, key);
1143     }
1144 
1145     if (obj->IsTypedArray()) {
1146         return JSTypedArray::DeleteProperty(thread, obj, key);
1147     }
1148 
1149     if (obj->IsSpecialContainer()) {
1150         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not delete property in Container Object", false);
1151     }
1152 
1153     return JSObject::DeleteProperty(thread, JSHandle<JSObject>(obj), key);
1154 }
1155 
1156 // 7.3.8 DeletePropertyOrThrow (O, P)
DeletePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1157 bool JSTaggedValue::DeletePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1158                                           const JSHandle<JSTaggedValue> &key)
1159 {
1160     if (!obj->IsECMAObject()) {
1161         THROW_TYPE_ERROR_AND_RETURN(thread, "Obj is not a valid object", false);
1162     }
1163     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1164 
1165     // 3. Let success be O.[[Delete]](P).
1166     bool success = DeleteProperty(thread, obj, key);
1167 
1168     // 4. ReturnIfAbrupt(success).
1169     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, success);
1170     // 5. If success is false, throw a TypeError exception
1171     if (!success) {
1172         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot delete property", false);
1173     }
1174     return success;
1175 }
1176 
1177 // 7.3.7 DefinePropertyOrThrow (O, P, desc)
DefinePropertyOrThrow(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc)1178 bool JSTaggedValue::DefinePropertyOrThrow(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1179                                           const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc)
1180 {
1181     // 1. Assert: Type(O) is Object.
1182     // 2. Assert: IsPropertyKey(P) is true.
1183     ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
1184     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1185     // 3. Let success be ? O.[[DefineOwnProperty]](P, desc).
1186     bool success = DefineOwnProperty(thread, obj, key, desc);
1187     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1188     // 4. If success is false, throw a TypeError exception.
1189     if (!success) {
1190         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot define property", false);
1191     }
1192     return success;
1193 }
1194 
DefineOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const PropertyDescriptor & desc,SCheckMode sCheckMode)1195 bool JSTaggedValue::DefineOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1196                                       const JSHandle<JSTaggedValue> &key, const PropertyDescriptor &desc,
1197                                       SCheckMode sCheckMode)
1198 {
1199     if (obj->IsJSArray()) {
1200         return JSArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1201     }
1202 
1203     if (obj->IsJSSharedArray()) {
1204         return JSSharedArray::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc, sCheckMode);
1205     }
1206 
1207     if (obj->IsJSProxy()) {
1208         return JSProxy::DefineOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1209     }
1210 
1211     if (obj->IsTypedArray()) {
1212         return JSTypedArray::DefineOwnProperty(thread, obj, key, desc);
1213     }
1214 
1215     if (obj->IsModuleNamespace()) {
1216         return ModuleNamespace::DefineOwnProperty(thread, obj, key, desc);
1217     }
1218 
1219     if (obj->IsSpecialContainer()) {
1220         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not defineProperty on Container Object", false);
1221     }
1222 
1223     return JSObject::DefineOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1224 }
1225 
GetOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1226 bool JSTaggedValue::GetOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1227                                    const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1228 {
1229     if (obj->IsJSProxy()) {
1230         return JSProxy::GetOwnProperty(thread, JSHandle<JSProxy>(obj), key, desc);
1231     }
1232     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1233         return JSTypedArray::GetOwnProperty(thread, obj, key, desc);
1234     }
1235     if (obj->IsModuleNamespace()) {
1236         return ModuleNamespace::GetOwnProperty(thread, obj, key, desc);
1237     }
1238     if (obj->IsSpecialContainer()) {
1239         return GetContainerProperty(thread, obj, key, desc);
1240     }
1241     return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1242 }
1243 
SetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & proto,bool isChangeProto)1244 bool JSTaggedValue::SetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1245                                  const JSHandle<JSTaggedValue> &proto, bool isChangeProto)
1246 {
1247     if (obj->IsJSShared() || proto->IsJSShared()) {
1248         THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(SetProtoWithSendable), false);
1249     }
1250 
1251     if (obj->IsJSProxy()) {
1252         return JSProxy::SetPrototype(thread, JSHandle<JSProxy>(obj), proto);
1253     }
1254     if (obj->IsModuleNamespace()) {
1255         return ModuleNamespace::SetPrototype(obj, proto);
1256     }
1257     if (obj->IsSpecialContainer() || !obj->IsECMAObject()) {
1258         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not set Prototype on Container or non ECMA Object", false);
1259     }
1260     if (obj->IsJSFunction() && proto->IsJSFunction()) {
1261         JSHandle<JSFunction> objFunc = JSHandle<JSFunction>::Cast(obj);
1262         JSTaggedValue objProtoOrHClass(objFunc->GetProtoOrHClass());
1263         if (objProtoOrHClass.IsJSHClass() && objFunc->IsDerivedConstructor()) {
1264             JSHandle<JSHClass> cachedJSHClass = JSHandle<JSHClass>(thread, objProtoOrHClass);
1265             objFunc->SetProtoOrHClass(thread, cachedJSHClass->GetPrototype());
1266         }
1267     }
1268 
1269     return JSObject::SetPrototype(thread, JSHandle<JSObject>(obj), proto, isChangeProto);
1270 }
1271 
GetPrototype(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1272 JSTaggedValue JSTaggedValue::GetPrototype(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1273 {
1274     if (!obj->IsECMAObject()) {
1275         THROW_TYPE_ERROR_AND_RETURN(thread, "Can not get Prototype on non ECMA Object", JSTaggedValue::Exception());
1276     }
1277     if (obj->IsJSProxy()) {
1278         return JSProxy::GetPrototype(thread, JSHandle<JSProxy>(obj));
1279     }
1280     return JSObject::GetPrototype(JSHandle<JSObject>(obj));
1281 }
1282 
PreventExtensions(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1283 bool JSTaggedValue::PreventExtensions(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1284 {
1285     if (obj->IsJSProxy()) {
1286         return JSProxy::PreventExtensions(thread, JSHandle<JSProxy>(obj));
1287     }
1288     if (obj->IsModuleNamespace()) {
1289         return ModuleNamespace::PreventExtensions();
1290     }
1291     return JSObject::PreventExtensions(thread, JSHandle<JSObject>(obj));
1292 }
1293 
GetOwnPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1294 JSHandle<TaggedArray> JSTaggedValue::GetOwnPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1295 {
1296     if (obj->IsJSProxy()) {
1297         return JSProxy::OwnPropertyKeys(thread, JSHandle<JSProxy>(obj));
1298     }
1299     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1300         return JSTypedArray::OwnPropertyKeys(thread, obj);
1301     }
1302     if (obj->IsSpecialContainer()) {
1303         return GetOwnContainerPropertyKeys(thread, obj);
1304     }
1305     if (obj->IsModuleNamespace()) {
1306         return ModuleNamespace::OwnPropertyKeys(thread, obj);
1307     }
1308     return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1309 }
1310 
GetAllPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t filter)1311 JSHandle<TaggedArray> JSTaggedValue::GetAllPropertyKeys(JSThread *thread,
1312                                                         const JSHandle<JSTaggedValue> &obj, uint32_t filter)
1313 {
1314     if (obj->IsJSProxy()) {
1315         return JSProxy::GetAllPropertyKeys(thread, JSHandle<JSProxy>(obj), filter);
1316     }
1317     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1318         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support TypedArray yet";
1319         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1320     }
1321     if (obj->IsSpecialContainer()) {
1322         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support SpecialContainer yet";
1323         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1324     }
1325     if (obj->IsModuleNamespace()) {
1326         LOG_ECMA(WARN) << "GetAllPropertyKeys do not support ModuleNamespace yet";
1327         return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1328     }
1329     return JSObject::GetAllPropertyKeys(thread, JSHandle<JSObject>(obj), filter);
1330 }
1331 
GetOwnEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1332 JSHandle<TaggedArray> JSTaggedValue::GetOwnEnumPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1333 {
1334     ASSERT(!obj->IsJSProxy());
1335     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1336         return JSTypedArray::OwnEnumPropertyKeys(thread, obj);
1337     }
1338     if (obj->IsSpecialContainer()) {
1339         return GetOwnContainerEnumPropertyKeys(thread, obj);
1340     }
1341     if (obj->IsModuleNamespace()) {
1342         return ModuleNamespace::OwnEnumPropertyKeys(thread, obj);
1343     }
1344     return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1345 }
1346 
1347 // 7.3.10 HasProperty (O, P)
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1348 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1349                                 const JSHandle<JSTaggedValue> &key)
1350 {
1351     if (obj->IsJSProxy()) {
1352         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), key);
1353     }
1354     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1355         return JSTypedArray::HasProperty(thread, obj, key);
1356     }
1357     if (obj->IsModuleNamespace()) {
1358         return ModuleNamespace::HasProperty(thread, obj, key);
1359     }
1360     if (obj->IsSpecialContainer()) {
1361         return HasContainerProperty(thread, obj, key);
1362     }
1363     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1364 }
1365 
HasProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,uint32_t key)1366 bool JSTaggedValue::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj, uint32_t key)
1367 {
1368     if (obj->IsJSProxy()) {
1369         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1370         return JSProxy::HasProperty(thread, JSHandle<JSProxy>(obj), keyHandle);
1371     }
1372     if (obj->IsTypedArray() || obj->IsSharedTypedArray()) {
1373         JSHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue(key));
1374         return JSTypedArray::HasProperty(thread, obj, keyHandle);
1375     }
1376     if (obj->IsSpecialContainer()) {
1377         return HasContainerProperty(thread, obj, JSHandle<JSTaggedValue>(thread, JSTaggedValue(key)));
1378     }
1379     return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1380 }
1381 
1382 // 7.3.11 HasOwnProperty (O, P)
HasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1383 bool JSTaggedValue::HasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1384                                    const JSHandle<JSTaggedValue> &key)
1385 {
1386     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1387 
1388     PropertyDescriptor desc(thread);
1389     return JSTaggedValue::GetOwnProperty(thread, obj, key, desc);
1390 }
1391 
GlobalHasOwnProperty(JSThread * thread,const JSHandle<JSTaggedValue> & key)1392 bool JSTaggedValue::GlobalHasOwnProperty(JSThread *thread, const JSHandle<JSTaggedValue> &key)
1393 {
1394     ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
1395 
1396     PropertyDescriptor desc(thread);
1397     return JSObject::GlobalGetOwnProperty(thread, key, desc);
1398 }
1399 
CanBeHeldWeakly(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1400 bool JSTaggedValue::CanBeHeldWeakly(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1401 {
1402     // 1. If v is an Object, return true.
1403     if (tagged->IsECMAObject()) {
1404         return true;
1405     }
1406     // 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
1407     if (tagged->IsSymbol()) {
1408         JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1409         auto *table = env->GetRegisterSymbols().GetObject<SymbolTable>();
1410         JSTaggedValue key = table->FindSymbol(tagged.GetTaggedValue());
1411         if (key.IsUndefined()) {
1412             return true;
1413         }
1414     }
1415     // 3. Return false.
1416     return false;
1417 }
1418 
ToIndex(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)1419 JSTaggedNumber JSTaggedValue::ToIndex(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
1420 {
1421     if (tagged->IsInt() && tagged->GetInt() >= 0) {
1422         return JSTaggedNumber(tagged.GetTaggedValue());
1423     }
1424     if (tagged->IsUndefined()) {
1425         return JSTaggedNumber(0);
1426     }
1427     JSTaggedNumber integerIndex = ToNumber(thread, tagged);
1428     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
1429     if (integerIndex.IsInt() && integerIndex.GetInt() >= 0) {
1430         return integerIndex;
1431     }
1432     double len = base::NumberHelper::TruncateDouble(integerIndex.GetNumber());
1433     if (len < 0.0 || len > SAFE_NUMBER) {
1434         THROW_RANGE_ERROR_AND_RETURN(thread, "integerIndex < 0 or integerIndex > SAFE_NUMBER",
1435                                      JSTaggedNumber::Exception());
1436     }
1437     return JSTaggedNumber(len);
1438 }
1439 
1440 // 9.4.2.4 ArraySetLength 3 to 7
ToArrayLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,uint32_t * output)1441 bool JSTaggedValue::ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output)
1442 {
1443     // 3. Let newLen be ToUint32(Desc.[[Value]]).
1444     uint32_t newLen = ToUint32(thread, tagged);
1445     // 4. ReturnIfAbrupt(newLen).
1446     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1447 
1448     // 5. Let numberLen be ToNumber(Desc.[[Value]]).
1449     JSTaggedNumber numberLen = ToNumber(thread, tagged);
1450     // 6. ReturnIfAbrupt(newLen).
1451     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1452 
1453     // 7. If newLen != numberLen, throw a RangeError exception.
1454     if (JSTaggedNumber(newLen) != numberLen) {
1455         THROW_RANGE_ERROR_AND_RETURN(thread, "Not a valid array length", false);
1456     }
1457 
1458     *output = newLen;
1459     return true;
1460 }
1461 
ToPrototypeOrObj(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1462 JSHandle<JSTaggedValue> JSTaggedValue::ToPrototypeOrObj(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1463 {
1464     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1465 
1466     if (obj->IsNumber()) {
1467         return JSHandle<JSTaggedValue>(thread,
1468                                        env->GetNumberFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1469     }
1470     if (obj->IsBoolean()) {
1471         return JSHandle<JSTaggedValue>(thread,
1472                                        env->GetBooleanFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1473     }
1474     if (obj->IsString()) {
1475         return JSHandle<JSTaggedValue>(thread,
1476                                        env->GetStringFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1477     }
1478     if (obj->IsSymbol()) {
1479         return JSHandle<JSTaggedValue>(thread,
1480                                        env->GetSymbolFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1481     }
1482     if (obj->IsBigInt()) {
1483         return JSHandle<JSTaggedValue>(thread,
1484                                        env->GetBigIntFunction().GetObject<JSFunction>()->GetFunctionPrototype());
1485     }
1486     return obj;
1487 }
1488 
GetSuperBase(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1489 JSTaggedValue JSTaggedValue::GetSuperBase(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1490 {
1491     if (obj->IsUndefined()) {
1492         return JSTaggedValue::Undefined();
1493     }
1494 
1495     ASSERT(obj->IsECMAObject());
1496     return JSTaggedValue::GetPrototype(thread, obj);
1497 }
1498 
HasContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1499 bool JSTaggedValue::HasContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1500                                          const JSHandle<JSTaggedValue> &key)
1501 {
1502     auto *hclass = obj->GetTaggedObject()->GetClass();
1503     JSType jsType = hclass->GetObjectType();
1504     switch (jsType) {
1505         case JSType::JS_API_ARRAY_LIST: {
1506             return JSHandle<JSAPIArrayList>::Cast(obj)->Has(key.GetTaggedValue());
1507         }
1508         case JSType::JS_API_QUEUE: {
1509             return JSHandle<JSAPIQueue>::Cast(obj)->Has(key.GetTaggedValue());
1510         }
1511         case JSType::JS_API_PLAIN_ARRAY: {
1512             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1513         }
1514         case JSType::JS_API_DEQUE: {
1515             return JSHandle<JSAPIDeque>::Cast(obj)->Has(key.GetTaggedValue());
1516         }
1517         case JSType::JS_API_STACK: {
1518             return JSHandle<JSAPIStack>::Cast(obj)->Has(key.GetTaggedValue());
1519         }
1520         case JSType::JS_API_LIST: {
1521             JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
1522             return list->Has(key.GetTaggedValue());
1523         }
1524         case JSType::JS_API_LINKED_LIST: {
1525             JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj);
1526             return linkedList->Has(key.GetTaggedValue());
1527         }
1528         case JSType::JS_API_HASH_MAP:
1529         case JSType::JS_API_HASH_SET:
1530         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1531         case JSType::JS_API_LIGHT_WEIGHT_SET:
1532         case JSType::JS_API_TREE_MAP:
1533         case JSType::JS_API_TREE_SET: {
1534             return JSObject::HasProperty(thread, JSHandle<JSObject>(obj), key);
1535         }
1536         case JSType::JS_API_VECTOR: {
1537             return JSHandle<JSAPIVector>::Cast(obj)->Has(key.GetTaggedValue());
1538         }
1539         case JSType::JS_API_BITVECTOR: {
1540             return JSHandle<JSAPIBitVector>::Cast(obj)->Has(key.GetTaggedValue());
1541         }
1542         default: {
1543             LOG_ECMA(FATAL) << "this branch is unreachable";
1544             UNREACHABLE();
1545         }
1546     }
1547     return false;
1548 }
1549 
GetOwnContainerPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1550 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerPropertyKeys(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
1551 {
1552     auto *hclass = obj->GetTaggedObject()->GetClass();
1553     JSType jsType = hclass->GetObjectType();
1554     switch (jsType) {
1555         case JSType::JS_API_ARRAY_LIST: {
1556             return JSAPIArrayList::OwnKeys(thread, JSHandle<JSAPIArrayList>::Cast(obj));
1557         }
1558         case JSType::JS_API_QUEUE: {
1559             return JSAPIQueue::OwnKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1560         }
1561         case JSType::JS_API_PLAIN_ARRAY: {
1562             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1563         }
1564         case JSType::JS_API_DEQUE: {
1565             return JSAPIDeque::OwnKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1566         }
1567         case JSType::JS_API_STACK: {
1568             return JSAPIStack::OwnKeys(thread, JSHandle<JSAPIStack>::Cast(obj));
1569         }
1570         case JSType::JS_API_LIST: {
1571             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1572         }
1573         case JSType::JS_API_LINKED_LIST: {
1574             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1575         }
1576         case JSType::JS_API_HASH_MAP:
1577         case JSType::JS_API_HASH_SET:
1578         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1579         case JSType::JS_API_LIGHT_WEIGHT_SET:
1580         case JSType::JS_API_TREE_MAP:
1581         case JSType::JS_API_TREE_SET: {
1582             return JSObject::GetOwnPropertyKeys(thread, JSHandle<JSObject>(obj));
1583         }
1584         case JSType::JS_API_VECTOR: {
1585             return JSAPIVector::OwnKeys(thread, JSHandle<JSAPIVector>::Cast(obj));
1586         }
1587         case JSType::JS_API_BITVECTOR: {
1588             return JSAPIBitVector::OwnKeys(thread, JSHandle<JSAPIBitVector>::Cast(obj));
1589         }
1590         default: {
1591             LOG_ECMA(FATAL) << "this branch is unreachable";
1592             UNREACHABLE();
1593         }
1594     }
1595     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1596 }
1597 
GetOwnContainerEnumPropertyKeys(JSThread * thread,const JSHandle<JSTaggedValue> & obj)1598 JSHandle<TaggedArray> JSTaggedValue::GetOwnContainerEnumPropertyKeys(JSThread *thread,
1599     const JSHandle<JSTaggedValue> &obj)
1600 {
1601     auto *hclass = obj->GetTaggedObject()->GetClass();
1602     JSType jsType = hclass->GetObjectType();
1603     switch (jsType) {
1604         case JSType::JS_API_QUEUE: {
1605             return JSAPIQueue::OwnEnumKeys(thread, JSHandle<JSAPIQueue>::Cast(obj));
1606         }
1607         case JSType::JS_API_DEQUE: {
1608             return JSAPIDeque::OwnEnumKeys(thread, JSHandle<JSAPIDeque>::Cast(obj));
1609         }
1610         case JSType::JS_API_LIST: {
1611             return JSAPIList::OwnKeys(thread, JSHandle<JSAPIList>::Cast(obj));
1612         }
1613         case JSType::JS_API_LINKED_LIST: {
1614             return JSAPILinkedList::OwnKeys(thread, JSHandle<JSAPILinkedList>::Cast(obj));
1615         }
1616         case JSType::JS_API_VECTOR:
1617         case JSType::JS_API_BITVECTOR:
1618         case JSType::JS_API_STACK:
1619         case JSType::JS_API_ARRAY_LIST:
1620         case JSType::JS_API_PLAIN_ARRAY:
1621         case JSType::JS_API_HASH_MAP:
1622         case JSType::JS_API_HASH_SET:
1623         case JSType::JS_API_LIGHT_WEIGHT_MAP:
1624         case JSType::JS_API_LIGHT_WEIGHT_SET:
1625         case JSType::JS_API_TREE_MAP:
1626         case JSType::JS_API_TREE_SET: {
1627             return JSObject::GetOwnEnumPropertyKeys(thread, JSHandle<JSObject>(obj));
1628         }
1629         default: {
1630             UNREACHABLE();
1631         }
1632     }
1633     return thread->GetEcmaVM()->GetFactory()->EmptyArray();
1634 }
1635 
GetContainerProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,PropertyDescriptor & desc)1636 bool JSTaggedValue::GetContainerProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1637                                          const JSHandle<JSTaggedValue> &key, PropertyDescriptor &desc)
1638 {
1639     if (key->IsInteger()) {
1640         auto *hclass = obj->GetTaggedObject()->GetClass();
1641         JSType jsType = hclass->GetObjectType();
1642         switch (jsType) {
1643             case JSType::JS_API_ARRAY_LIST: {
1644                 return JSAPIArrayList::GetOwnProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1645             }
1646             case JSType::JS_API_QUEUE: {
1647                 return JSAPIQueue::GetOwnProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1648             }
1649             case JSType::JS_API_DEQUE: {
1650                 return JSAPIDeque::GetOwnProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1651             }
1652             case JSType::JS_API_STACK: {
1653                 return JSAPIStack::GetOwnProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1654             }
1655             case JSType::JS_API_LIST: {
1656                 return JSAPIList::GetOwnProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1657             }
1658             case JSType::JS_API_LINKED_LIST: {
1659                 return JSAPILinkedList::GetOwnProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1660             }
1661             case JSType::JS_API_PLAIN_ARRAY: {
1662                 return JSAPIPlainArray::GetOwnProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1663             }
1664             case JSType::JS_API_VECTOR: {
1665                 return JSAPIVector::GetOwnProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1666             }
1667             case JSType::JS_API_BITVECTOR: {
1668                 return JSAPIBitVector::GetOwnProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1669             }
1670             default: {
1671                 return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1672             }
1673         }
1674     } else {
1675         return JSObject::GetOwnProperty(thread, JSHandle<JSObject>(obj), key, desc);
1676     }
1677     return false;
1678 }
1679 
StringToNumber(JSTaggedValue tagged)1680 JSTaggedNumber JSTaggedValue::StringToNumber(JSTaggedValue tagged)
1681 {
1682     EcmaStringAccessor strAccessor(tagged);
1683     size_t strLen = strAccessor.GetLength();
1684     if (strLen == 0) {
1685         return JSTaggedNumber(0);
1686     }
1687     if (strLen < MAX_ELEMENT_INDEX_LEN && strAccessor.IsUtf8()) {
1688         uint32_t index;
1689         // fast path: get integer from string's hash value
1690         if (strAccessor.TryToGetInteger(&index)) {
1691             return JSTaggedNumber(index);
1692         }
1693         Span<const uint8_t> str = strAccessor.FastToUtf8Span();
1694         if (strAccessor.GetLength() == 0) {
1695             return JSTaggedNumber(0);
1696         }
1697         auto [isSuccess, result] = base::NumberHelper::FastStringToNumber(str.begin(), str.end(), tagged);
1698         if (isSuccess) {
1699             return result;
1700         }
1701     }
1702     CVector<uint8_t> buf;
1703     Span<const uint8_t> str = strAccessor.ToUtf8Span(buf);
1704     double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
1705                                                   base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
1706     return JSTaggedNumber(d);
1707 }
1708 
ToNumeric(JSThread * thread,JSHandle<JSTaggedValue> tagged)1709 JSHandle<JSTaggedValue> JSTaggedValue::ToNumeric(JSThread *thread, JSHandle<JSTaggedValue> tagged)
1710 {
1711     // 1. Let primValue be ? ToPrimitive(value, number)
1712     JSTaggedValue primValue = ToPrimitive(thread, tagged, PREFER_NUMBER);
1713     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1714     // 2. If Type(primValue) is BigInt, return primValue.
1715     if (primValue.IsBigInt()) {
1716         return JSHandle<JSTaggedValue>(thread, primValue);
1717     }
1718     // 3. Return ? ToNumber(primValue).
1719     JSTaggedNumber number = ToNumber(thread, primValue);
1720     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1721     JSHandle<JSTaggedValue> value(thread, number);
1722     return value;
1723 }
1724 
GetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key)1725 OperationResult JSTaggedValue::GetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1726                                                 const JSHandle<JSTaggedValue> &key)
1727 {
1728     if (key->IsInteger()) {
1729         auto *hclass = obj->GetTaggedObject()->GetClass();
1730         JSType jsType = hclass->GetObjectType();
1731         switch (jsType) {
1732             case JSType::JS_API_ARRAY_LIST: {
1733                 return JSAPIArrayList::GetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key);
1734             }
1735             case JSType::JS_API_LIST: {
1736                 return JSAPIList::GetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key);
1737             }
1738             case JSType::JS_API_LINKED_LIST: {
1739                 return JSAPILinkedList::GetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key);
1740             }
1741             case JSType::JS_API_QUEUE: {
1742                 return JSAPIQueue::GetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key);
1743             }
1744             case JSType::JS_API_DEQUE: {
1745                 return JSAPIDeque::GetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key);
1746             }
1747             case JSType::JS_API_STACK: {
1748                 return JSAPIStack::GetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key);
1749             }
1750             case JSType::JS_API_PLAIN_ARRAY: {
1751                 return JSAPIPlainArray::GetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key);
1752             }
1753             case JSType::JS_API_VECTOR: {
1754                 return JSAPIVector::GetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key);
1755             }
1756             case JSType::JS_API_BITVECTOR: {
1757                 return JSAPIBitVector::GetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key);
1758             }
1759             default: {
1760                 return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1761             }
1762         }
1763     } else {
1764         return JSObject::GetProperty(thread, JSHandle<JSObject>(obj), key);
1765     }
1766     return OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false));
1767 }
1768 
SetJSAPIProperty(JSThread * thread,const JSHandle<JSTaggedValue> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)1769 bool JSTaggedValue::SetJSAPIProperty(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
1770                                      const JSHandle<JSTaggedValue> &key,
1771                                      const JSHandle<JSTaggedValue> &value)
1772 {
1773     if (key->IsInteger()) {
1774         auto *hclass = obj->GetTaggedObject()->GetClass();
1775         JSType jsType = hclass->GetObjectType();
1776         switch (jsType) {
1777             case JSType::JS_API_ARRAY_LIST: {
1778                 return JSAPIArrayList::SetProperty(thread, JSHandle<JSAPIArrayList>::Cast(obj), key, value);
1779             }
1780             case JSType::JS_API_LIST: {
1781                 return JSAPIList::SetProperty(thread, JSHandle<JSAPIList>::Cast(obj), key, value);
1782             }
1783             case JSType::JS_API_LINKED_LIST: {
1784                 JSAPILinkedList::SetProperty(thread, JSHandle<JSAPILinkedList>::Cast(obj), key, value);
1785                 return true;
1786             }
1787             case JSType::JS_API_QUEUE: {
1788                 return JSAPIQueue::SetProperty(thread, JSHandle<JSAPIQueue>::Cast(obj), key, value);
1789             }
1790             case JSType::JS_API_DEQUE: {
1791                 return JSAPIDeque::SetProperty(thread, JSHandle<JSAPIDeque>::Cast(obj), key, value);
1792             }
1793             case JSType::JS_API_STACK: {
1794                 return JSAPIStack::SetProperty(thread, JSHandle<JSAPIStack>::Cast(obj), key, value);
1795             }
1796             case JSType::JS_API_PLAIN_ARRAY: {
1797                 return JSAPIPlainArray::SetProperty(thread, JSHandle<JSAPIPlainArray>::Cast(obj), key, value);
1798             }
1799             case JSType::JS_API_VECTOR: {
1800                 return JSAPIVector::SetProperty(thread, JSHandle<JSAPIVector>::Cast(obj), key, value);
1801             }
1802             case JSType::JS_API_BITVECTOR: {
1803                 return JSAPIBitVector::SetProperty(thread, JSHandle<JSAPIBitVector>::Cast(obj), key, value);
1804             }
1805             default: {
1806                 return JSObject::SetProperty(thread, JSHandle<JSObject>::Cast(obj), key, value);
1807             }
1808         }
1809     } else {
1810         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1811     }
1812     THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot set property on Container", false);
1813 }
1814 
1815 }  // namespace panda::ecmascript
1816