1 /*
2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_TAGGED_VALUE_INL_H
17 #define ECMASCRIPT_TAGGED_VALUE_INL_H
18
19 #include "ecmascript/js_tagged_value.h"
20
21 #include "ecmascript/accessor_data.h"
22 #include "ecmascript/base/error_helper.h"
23 #include "ecmascript/base/number_helper.h"
24 #include "ecmascript/base/string_helper.h"
25 #include "ecmascript/ecma_macros.h"
26 #include "ecmascript/ecma_runtime_call_info.h"
27 #include "ecmascript/ecma_string-inl.h"
28 #include "ecmascript/js_bigint.h"
29 #include "ecmascript/js_hclass-inl.h"
30 #include "ecmascript/js_object.h"
31 #include "ecmascript/js_proxy.h"
32 #include "ecmascript/js_symbol.h"
33 #include "ecmascript/js_tagged_number.h"
34 #include "ecmascript/js_thread.h"
35 #include "ecmascript/mem/c_containers.h"
36 #include "ecmascript/mem/tagged_object-inl.h"
37 #include "ecmascript/object_factory.h"
38
39 namespace panda::ecmascript {
40 // ecma6 7.1 Type Conversion
41 static constexpr double SAFE_NUMBER = 9007199254740991LL;
42 static constexpr uint32_t MAX_INDEX_LEN = 10;
43
ToBoolean()44 inline bool JSTaggedValue::ToBoolean() const
45 {
46 if (IsInt()) {
47 return GetInt() != 0;
48 }
49 if (IsDouble()) {
50 double d = GetDouble();
51 return !std::isnan(d) && d != 0;
52 }
53 switch (GetRawData()) {
54 case JSTaggedValue::VALUE_UNDEFINED:
55 [[fallthrough]];
56 case JSTaggedValue::VALUE_HOLE:
57 [[fallthrough]];
58 case JSTaggedValue::VALUE_NULL:
59 [[fallthrough]];
60 case JSTaggedValue::VALUE_FALSE: {
61 return false;
62 }
63 case JSTaggedValue::VALUE_TRUE: {
64 return true;
65 }
66 default: {
67 break;
68 }
69 }
70
71 if (IsBigInt()) {
72 BigInt *bigint = BigInt::Cast(GetTaggedObject());
73 return !bigint->IsZero();
74 }
75 if (IsHeapObject()) {
76 TaggedObject *obj = GetTaggedObject();
77 if (IsString()) {
78 auto str = static_cast<EcmaString *>(obj);
79 return str->GetLength() != 0;
80 }
81 return true;
82 }
83
84 UNREACHABLE();
85 }
86
ToNumber(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)87 inline JSTaggedNumber JSTaggedValue::ToNumber(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
88 {
89 if (tagged->IsInt() || tagged->IsDouble()) {
90 return JSTaggedNumber(tagged.GetTaggedValue());
91 }
92
93 switch (tagged->GetRawData()) {
94 case JSTaggedValue::VALUE_UNDEFINED:
95 case JSTaggedValue::VALUE_HOLE: {
96 return JSTaggedNumber(base::NAN_VALUE);
97 }
98 case JSTaggedValue::VALUE_TRUE: {
99 return JSTaggedNumber(1);
100 }
101 case JSTaggedValue::VALUE_FALSE:
102 case JSTaggedValue::VALUE_NULL: {
103 return JSTaggedNumber(0);
104 }
105 default: {
106 break;
107 }
108 }
109
110 if (tagged->IsString()) {
111 Span<const uint8_t> str;
112 auto strObj = static_cast<EcmaString *>(tagged->GetTaggedObject());
113 size_t strLen = strObj->GetLength();
114 if (strLen == 0) {
115 return JSTaggedNumber(0);
116 }
117 [[maybe_unused]] CVector<uint8_t> buf; // Span will use buf.data(), shouldn't define inside 'if'
118 if (UNLIKELY(strObj->IsUtf16())) {
119 size_t len = base::utf_helper::Utf16ToUtf8Size(strObj->GetDataUtf16(), strLen) - 1;
120 buf.reserve(len);
121 len = base::utf_helper::ConvertRegionUtf16ToUtf8(strObj->GetDataUtf16(), buf.data(), strLen, len, 0);
122 str = Span<const uint8_t>(buf.data(), len);
123 } else {
124 str = Span<const uint8_t>(strObj->GetDataUtf8(), strLen);
125 }
126 double d = base::NumberHelper::StringToDouble(str.begin(), str.end(), 0,
127 base::ALLOW_BINARY + base::ALLOW_OCTAL + base::ALLOW_HEX);
128 return JSTaggedNumber(d);
129 }
130 if (tagged->IsECMAObject()) {
131 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged, PREFER_NUMBER));
132 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
133 return ToNumber(thread, primValue);
134 }
135 if (tagged->IsSymbol()) {
136 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a number", JSTaggedNumber::Exception());
137 }
138 if (tagged->IsBigInt()) {
139 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a BigInt value to a number", JSTaggedNumber::Exception());
140 }
141 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a number", JSTaggedNumber::Exception());
142 }
143
ToBigInt(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)144 inline JSTaggedValue JSTaggedValue::ToBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
145 {
146 JSHandle<JSTaggedValue> primValue(thread, ToPrimitive(thread, tagged));
147 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
148 switch (primValue->GetRawData()) {
149 case JSTaggedValue::VALUE_UNDEFINED:
150 case JSTaggedValue::VALUE_NULL: {
151 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a undefine or null value to a BigInt",
152 JSTaggedValue::Exception());
153 }
154 case JSTaggedValue::VALUE_TRUE: {
155 return BigInt::Int32ToBigInt(thread, 1).GetTaggedValue();
156 }
157 case JSTaggedValue::VALUE_FALSE: {
158 return BigInt::Int32ToBigInt(thread, 0).GetTaggedValue();
159 }
160 default: {
161 break;
162 }
163 }
164
165 if (primValue->IsNumber()) {
166 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Number value to a BigInt", JSTaggedNumber::Exception());
167 }
168 if (primValue->IsString()) {
169 JSHandle<JSTaggedValue> value(thread, base::NumberHelper::StringToBigInt(thread, primValue));
170 if (value->IsBigInt()) {
171 return value.GetTaggedValue();
172 }
173 THROW_SYNTAX_ERROR_AND_RETURN(thread, "Cannot convert string to a BigInt,"
174 "because not allow Infinity, decimal points, or exponents",
175 JSTaggedValue::Exception());
176 }
177 if (primValue->IsSymbol()) {
178 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Symbol value to a BigInt", JSTaggedNumber::Exception());
179 }
180 if (primValue->IsBigInt()) {
181 return primValue.GetTaggedValue();
182 }
183 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert a Unknown value to a BigInt", JSTaggedNumber::Exception());
184 }
185
ToBigInt64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)186 inline JSTaggedValue JSTaggedValue::ToBigInt64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
187 {
188 JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
189 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
190 JSHandle<BigInt> exponent = BigInt::Int32ToBigInt(thread, 64); // 64 : bits
191 JSHandle<BigInt> exponentone = BigInt::Int32ToBigInt(thread, 63); // 63 : bits
192 JSHandle<BigInt> base = BigInt::Int32ToBigInt(thread, 2); // 2 : base value
193 JSHandle<BigInt> tVal = BigInt::Exponentiate(thread, base, exponent);
194 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
195 JSHandle<BigInt> int64bitVal = BigInt::FloorMod(thread, value, tVal);
196 JSHandle<BigInt> resValue = BigInt::Exponentiate(thread, base, exponentone);
197 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
198 if (!BigInt::LessThan(int64bitVal.GetTaggedValue(), resValue.GetTaggedValue())) {
199 return BigInt::Subtract(thread, int64bitVal, tVal).GetTaggedValue();
200 } else {
201 return int64bitVal.GetTaggedValue();
202 }
203 }
204
ToBigUint64(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)205 inline JSTaggedValue JSTaggedValue::ToBigUint64(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
206 {
207 JSHandle<BigInt> value(thread, ToBigInt(thread, tagged));
208 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
209 JSHandle<BigInt> exponent = BigInt::Int32ToBigInt(thread, 64); // 64 : exponet value
210 JSHandle<BigInt> base = BigInt::Int32ToBigInt(thread, 2); // 2 : base value
211 JSHandle<BigInt> tVal = BigInt::Exponentiate(thread, base, exponent);
212 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
213 return BigInt::FloorMod(thread, value, tVal).GetTaggedValue();
214 }
215
ToInteger(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)216 inline JSTaggedNumber JSTaggedValue::ToInteger(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
217 {
218 JSTaggedNumber number = ToNumber(thread, tagged);
219 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
220
221 return JSTaggedNumber(base::NumberHelper::TruncateDouble(number.GetNumber()));
222 }
223
ToInt32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)224 inline int32_t JSTaggedValue::ToInt32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
225 {
226 JSTaggedNumber number = ToNumber(thread, tagged);
227 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
228 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT32_BITS);
229 }
230
ToUint32(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)231 inline uint32_t JSTaggedValue::ToUint32(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
232 {
233 return ToInt32(thread, tagged);
234 }
235
ToInt16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)236 inline int16_t JSTaggedValue::ToInt16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
237 {
238 JSTaggedNumber number = ToNumber(thread, tagged);
239 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
240
241 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT16_BITS);
242 }
243
ToUint16(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)244 inline uint16_t JSTaggedValue::ToUint16(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
245 {
246 return ToInt16(thread, tagged);
247 }
248
ToInt8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)249 inline int8_t JSTaggedValue::ToInt8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
250 {
251 JSTaggedNumber number = ToNumber(thread, tagged);
252 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
253
254 return base::NumberHelper::DoubleToInt(number.GetNumber(), base::INT8_BITS);
255 }
256
ToUint8(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)257 inline uint8_t JSTaggedValue::ToUint8(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
258 {
259 return ToInt8(thread, tagged);
260 }
261
ToUint8Clamp(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)262 inline uint8_t JSTaggedValue::ToUint8Clamp(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
263 {
264 JSTaggedNumber number = ToNumber(thread, tagged);
265 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
266
267 double d = number.GetNumber();
268 if (std::isnan(d) || d <= 0) {
269 return 0;
270 }
271 if (d >= UINT8_MAX) {
272 return UINT8_MAX;
273 }
274
275 return lrint(d);
276 }
277
ToLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)278 inline JSTaggedNumber JSTaggedValue::ToLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged)
279 {
280 JSTaggedNumber len = ToInteger(thread, tagged);
281 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedNumber::Exception());
282 if (len.GetNumber() < 0.0) {
283 return JSTaggedNumber(static_cast<double>(0));
284 }
285 if (len.GetNumber() > SAFE_NUMBER) {
286 return JSTaggedNumber(static_cast<double>(SAFE_NUMBER));
287 }
288 return len;
289 }
290
291 // ecma6 7.2 Testing and Comparison Operations
RequireObjectCoercible(JSThread * thread,const JSHandle<JSTaggedValue> & tagged)292 inline JSHandle<JSTaggedValue> JSTaggedValue::RequireObjectCoercible(JSThread *thread,
293 const JSHandle<JSTaggedValue> &tagged)
294 {
295 if (tagged->IsUndefined() || tagged->IsNull()) {
296 THROW_TYPE_ERROR_AND_RETURN(thread, "RequireObjectCoercible",
297 JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
298 }
299 return tagged;
300 }
301
IsCallable()302 inline bool JSTaggedValue::IsCallable() const
303 {
304 return IsHeapObject() && GetTaggedObject()->GetClass()->IsCallable();
305 }
306
IsConstructor()307 inline bool JSTaggedValue::IsConstructor() const
308 {
309 return IsHeapObject() && GetTaggedObject()->GetClass()->IsConstructor();
310 }
311
IsExtensible(JSThread * thread)312 inline bool JSTaggedValue::IsExtensible(JSThread *thread) const
313 {
314 if (UNLIKELY(IsJSProxy())) {
315 return JSProxy::IsExtensible(thread, JSHandle<JSProxy>(thread, *this));
316 }
317
318 return IsHeapObject() && GetTaggedObject()->GetClass()->IsExtensible();
319 }
320
IsClassConstructor()321 inline bool JSTaggedValue::IsClassConstructor() const
322 {
323 return IsHeapObject() && GetTaggedObject()->GetClass()->IsClassConstructor();
324 }
325
IsClassPrototype()326 inline bool JSTaggedValue::IsClassPrototype() const
327 {
328 return IsHeapObject() && GetTaggedObject()->GetClass()->IsClassPrototype();
329 }
330
IsPropertyKey(const JSHandle<JSTaggedValue> & key)331 inline bool JSTaggedValue::IsPropertyKey(const JSHandle<JSTaggedValue> &key)
332 {
333 return key->IsStringOrSymbol() || key->IsNumber();
334 }
335
SameValue(const JSTaggedValue & x,const JSTaggedValue & y)336 inline bool JSTaggedValue::SameValue(const JSTaggedValue &x, const JSTaggedValue &y)
337 {
338 // same object or special type must be same value
339 if (x == y) {
340 return true;
341 }
342 if (x.IsNumber() && y.IsNumber()) {
343 return SameValueNumberic(x, y);
344 }
345 if (x.IsString() && y.IsString()) {
346 return EcmaString::StringsAreEqual(static_cast<EcmaString *>(x.GetTaggedObject()),
347 static_cast<EcmaString *>(y.GetTaggedObject()));
348 }
349 if (x.IsBigInt() && y.IsBigInt()) {
350 return BigInt::SameValue(x, y);
351 }
352 return false;
353 }
354
SameValue(const JSHandle<JSTaggedValue> & xHandle,const JSHandle<JSTaggedValue> & yHandle)355 inline bool JSTaggedValue::SameValue(const JSHandle<JSTaggedValue> &xHandle, const JSHandle<JSTaggedValue> &yHandle)
356 {
357 return SameValue(xHandle.GetTaggedValue(), yHandle.GetTaggedValue());
358 }
359
SameValueZero(const JSTaggedValue & x,const JSTaggedValue & y)360 inline bool JSTaggedValue::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y)
361 {
362 if (x == y) {
363 return true;
364 }
365
366 if (x.IsNumber() && y.IsNumber()) {
367 double xValue = x.ExtractNumber();
368 double yValue = y.ExtractNumber();
369 // Compare xValue with yValue to deal with -0.0
370 return (xValue == yValue) || (std::isnan(xValue) && std::isnan(yValue));
371 }
372
373 if (x.IsString() && y.IsString()) {
374 return EcmaString::StringsAreEqual(static_cast<EcmaString *>(x.GetTaggedObject()),
375 static_cast<EcmaString *>(y.GetTaggedObject()));
376 }
377 if (x.IsBigInt() && y.IsBigInt()) {
378 return BigInt::SameValueZero(x, y);
379 }
380 return false;
381 }
382
SameValueNumberic(const JSTaggedValue & x,const JSTaggedValue & y)383 inline bool JSTaggedValue::SameValueNumberic(const JSTaggedValue &x, const JSTaggedValue &y)
384 {
385 double xValue = x.ExtractNumber();
386 double yValue = y.ExtractNumber();
387 // SameNumberValue(NaN, NaN) is true.
388 if (xValue != yValue) {
389 return std::isnan(xValue) && std::isnan(yValue);
390 }
391 // SameNumberValue(0.0, -0.0) is false.
392 return (std::signbit(xValue) == std::signbit(yValue));
393 }
394
Less(JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)395 inline bool JSTaggedValue::Less(JSThread *thread, const JSHandle<JSTaggedValue> &x, const JSHandle<JSTaggedValue> &y)
396 {
397 ComparisonResult result = Compare(thread, x, y);
398 return result == ComparisonResult::LESS;
399 }
400
StrictNumberEquals(double x,double y)401 inline bool JSTaggedValue::StrictNumberEquals(double x, double y)
402 {
403 // Must check explicitly for NaN's on Windows, but -0 works fine.
404 if (std::isnan(x) || std::isnan(y)) {
405 return false;
406 }
407 return x == y;
408 }
409
StrictEqual(const JSThread * thread,const JSHandle<JSTaggedValue> & x,const JSHandle<JSTaggedValue> & y)410 inline bool JSTaggedValue::StrictEqual([[maybe_unused]] const JSThread *thread, const JSHandle<JSTaggedValue> &x,
411 const JSHandle<JSTaggedValue> &y)
412 {
413 if (x->IsNumber() && y->IsNumber()) {
414 return StrictNumberEquals(x->ExtractNumber(), y->ExtractNumber());
415 }
416
417 if (x.GetTaggedValue() == y.GetTaggedValue()) {
418 return true;
419 }
420 if (x->IsString() && y->IsString()) {
421 return EcmaString::StringsAreEqual(x.GetObject<EcmaString>(), y.GetObject<EcmaString>());
422 }
423 if (x->IsBigInt() && y->IsBigInt()) {
424 return BigInt::Equal(x.GetTaggedValue(), y.GetTaggedValue());
425 }
426 return false;
427 }
428
StrictNumberCompare(double x,double y)429 inline ComparisonResult JSTaggedValue::StrictNumberCompare(double x, double y)
430 {
431 if (std::isnan(x) || std::isnan(y)) {
432 return ComparisonResult::UNDEFINED;
433 }
434 if (x < y) {
435 return ComparisonResult::LESS;
436 }
437 if (x > y) {
438 return ComparisonResult::GREAT;
439 }
440 return ComparisonResult::EQUAL;
441 }
442
IsNumber()443 inline bool JSTaggedValue::IsNumber() const
444 {
445 return IsInt() || IsDouble();
446 }
447
IsString()448 inline bool JSTaggedValue::IsString() const
449 {
450 return IsHeapObject() && GetTaggedObject()->GetClass()->IsString();
451 }
452
IsBigInt()453 inline bool JSTaggedValue::IsBigInt() const
454 {
455 return IsHeapObject() && GetTaggedObject()->GetClass()->IsBigInt();
456 }
457
IsStringOrSymbol()458 inline bool JSTaggedValue::IsStringOrSymbol() const
459 {
460 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStringOrSymbol();
461 }
462
IsTaggedArray()463 inline bool JSTaggedValue::IsTaggedArray() const
464 {
465 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTaggedArray();
466 }
467
IsNativePointer()468 inline bool JSTaggedValue::IsNativePointer() const
469 {
470 return IsJSNativePointer();
471 }
472
IsJSNativePointer()473 inline bool JSTaggedValue::IsJSNativePointer() const
474 {
475 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSNativePointer();
476 }
477
IsSymbol()478 inline bool JSTaggedValue::IsSymbol() const
479 {
480 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSSymbol();
481 }
482
IsJSProxy()483 inline bool JSTaggedValue::IsJSProxy() const
484 {
485 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxy();
486 }
487
IsBoolean()488 inline bool JSTaggedValue::IsBoolean() const
489 {
490 return IsTrue() || IsFalse();
491 }
492
IsJSObject()493 inline bool JSTaggedValue::IsJSObject() const
494 {
495 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSObject();
496 }
497
IsECMAObject()498 inline bool JSTaggedValue::IsECMAObject() const
499 {
500 return IsHeapObject() && GetTaggedObject()->GetClass()->IsECMAObject();
501 }
502
IsJSPromise()503 inline bool JSTaggedValue::IsJSPromise() const
504 {
505 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPromise();
506 }
507
IsRecord()508 inline bool JSTaggedValue::IsRecord() const
509 {
510 return IsHeapObject() && GetTaggedObject()->GetClass()->IsRecord();
511 }
512
IsPromiseReaction()513 inline bool JSTaggedValue::IsPromiseReaction() const
514 {
515 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPromiseReaction();
516 }
517
IsJSPromiseReactionFunction()518 inline bool JSTaggedValue::IsJSPromiseReactionFunction() const
519 {
520 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPromiseReactionFunction();
521 }
522
IsProgram()523 inline bool JSTaggedValue::IsProgram() const
524 {
525 return IsHeapObject() && GetTaggedObject()->GetClass()->IsProgram();
526 }
527
IsJSPromiseExecutorFunction()528 inline bool JSTaggedValue::IsJSPromiseExecutorFunction() const
529 {
530 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPromiseExecutorFunction();
531 }
532
IsJSPromiseAllResolveElementFunction()533 inline bool JSTaggedValue::IsJSPromiseAllResolveElementFunction() const
534 {
535 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPromiseAllResolveElementFunction();
536 }
537
IsCompletionRecord()538 inline bool JSTaggedValue::IsCompletionRecord() const
539 {
540 return IsHeapObject() && GetTaggedObject()->GetClass()->IsCompletionRecord();
541 }
542
IsResolvingFunctionsRecord()543 inline bool JSTaggedValue::IsResolvingFunctionsRecord() const
544 {
545 return IsHeapObject() && GetTaggedObject()->GetClass()->IsResolvingFunctionsRecord();
546 }
547
IsPromiseRecord()548 inline bool JSTaggedValue::IsPromiseRecord() const
549 {
550 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPromiseRecord();
551 }
552
IsJSLocale()553 inline bool JSTaggedValue::IsJSLocale() const
554 {
555 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSLocale();
556 }
557
IsJSIntl()558 inline bool JSTaggedValue::IsJSIntl() const
559 {
560 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSIntl();
561 }
562
IsJSDateTimeFormat()563 inline bool JSTaggedValue::IsJSDateTimeFormat() const
564 {
565 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSDateTimeFormat();
566 }
567
IsJSRelativeTimeFormat()568 inline bool JSTaggedValue::IsJSRelativeTimeFormat() const
569 {
570 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSRelativeTimeFormat();
571 }
572
IsJSNumberFormat()573 inline bool JSTaggedValue::IsJSNumberFormat() const
574 {
575 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSNumberFormat();
576 }
577
IsJSCollator()578 inline bool JSTaggedValue::IsJSCollator() const
579 {
580 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSCollator();
581 }
582
IsJSPluralRules()583 inline bool JSTaggedValue::IsJSPluralRules() const
584 {
585 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSPluralRules();
586 }
587
IsJSAPIArrayList()588 inline bool JSTaggedValue::IsJSAPIArrayList() const
589 {
590 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPIArrayList();
591 }
592
IsJSAPITreeMap()593 inline bool JSTaggedValue::IsJSAPITreeMap() const
594 {
595 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPITreeMap();
596 }
597
IsJSAPITreeSet()598 inline bool JSTaggedValue::IsJSAPITreeSet() const
599 {
600 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPITreeSet();
601 }
602
IsSpecialContainer()603 inline bool JSTaggedValue::IsSpecialContainer() const
604 {
605 return IsHeapObject() && GetTaggedObject()->GetClass()->IsSpecialContainer();
606 }
607
IsPromiseIteratorRecord()608 inline bool JSTaggedValue::IsPromiseIteratorRecord() const
609 {
610 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPromiseIteratorRecord();
611 }
612
IsPromiseCapability()613 inline bool JSTaggedValue::IsPromiseCapability() const
614 {
615 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPromiseCapability();
616 }
617
IsJSError()618 inline bool JSTaggedValue::IsJSError() const
619 {
620 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSError();
621 }
622
IsMicroJobQueue()623 inline bool JSTaggedValue::IsMicroJobQueue() const
624 {
625 return IsHeapObject() && GetTaggedObject()->GetClass()->IsMicroJobQueue();
626 }
627
IsPendingJob()628 inline bool JSTaggedValue::IsPendingJob() const
629 {
630 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPendingJob();
631 }
632
IsArguments()633 inline bool JSTaggedValue::IsArguments() const
634 {
635 return IsHeapObject() && GetTaggedObject()->GetClass()->IsArguments();
636 }
637
IsDate()638 inline bool JSTaggedValue::IsDate() const
639 {
640 return IsHeapObject() && GetTaggedObject()->GetClass()->IsDate();
641 }
642
IsArray(JSThread * thread)643 inline bool JSTaggedValue::IsArray(JSThread *thread) const
644 {
645 if (!IsHeapObject()) {
646 return false;
647 }
648 JSHClass *jsHclass = GetTaggedObject()->GetClass();
649 if (jsHclass->IsJSArray()) {
650 return true;
651 }
652
653 if (jsHclass->IsJSProxy()) {
654 return JSProxy::Cast(GetTaggedObject())->IsArray(thread);
655 }
656 return false;
657 }
658
IsJSArray()659 inline bool JSTaggedValue::IsJSArray() const
660 {
661 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSArray();
662 }
663
IsStableJSArray(JSThread * thread)664 inline bool JSTaggedValue::IsStableJSArray(JSThread *thread) const
665 {
666 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArray() &&
667 !thread->IsStableArrayElementsGuardiansInvalid();
668 }
669
IsStableJSArguments(JSThread * thread)670 inline bool JSTaggedValue::IsStableJSArguments(JSThread *thread) const
671 {
672 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableJSArguments() &&
673 !thread->IsStableArrayElementsGuardiansInvalid();
674 }
675
HasStableElements(JSThread * thread)676 inline bool JSTaggedValue::HasStableElements(JSThread *thread) const
677 {
678 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStableElements() &&
679 !thread->IsStableArrayElementsGuardiansInvalid();
680 }
681
IsTypedArray()682 inline bool JSTaggedValue::IsTypedArray() const
683 {
684 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTypedArray();
685 }
686
IsJSTypedArray()687 inline bool JSTaggedValue::IsJSTypedArray() const
688 {
689 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSTypedArray();
690 }
691
IsJSInt8Array()692 inline bool JSTaggedValue::IsJSInt8Array() const
693 {
694 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSInt8Array();
695 }
696
IsJSUint8Array()697 inline bool JSTaggedValue::IsJSUint8Array() const
698 {
699 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSUint8Array();
700 }
701
IsJSUint8ClampedArray()702 inline bool JSTaggedValue::IsJSUint8ClampedArray() const
703 {
704 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSUint8ClampedArray();
705 }
706
IsJSInt16Array()707 inline bool JSTaggedValue::IsJSInt16Array() const
708 {
709 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSInt16Array();
710 }
711
IsJSUint16Array()712 inline bool JSTaggedValue::IsJSUint16Array() const
713 {
714 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSUint16Array();
715 }
716
IsJSInt32Array()717 inline bool JSTaggedValue::IsJSInt32Array() const
718 {
719 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSInt32Array();
720 }
721
IsJSUint32Array()722 inline bool JSTaggedValue::IsJSUint32Array() const
723 {
724 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSUint32Array();
725 }
726
IsJSFloat32Array()727 inline bool JSTaggedValue::IsJSFloat32Array() const
728 {
729 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSFloat32Array();
730 }
731
IsJSFloat64Array()732 inline bool JSTaggedValue::IsJSFloat64Array() const
733 {
734 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSFloat64Array();
735 }
736
IsJSMap()737 inline bool JSTaggedValue::IsJSMap() const
738 {
739 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSMap();
740 }
741
IsJSWeakMap()742 inline bool JSTaggedValue::IsJSWeakMap() const
743 {
744 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSWeakMap();
745 }
746
IsJSWeakSet()747 inline bool JSTaggedValue::IsJSWeakSet() const
748 {
749 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSWeakSet();
750 }
751
IsJSSet()752 inline bool JSTaggedValue::IsJSSet() const
753 {
754 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSSet();
755 }
756
IsJSRegExp()757 inline bool JSTaggedValue::IsJSRegExp() const
758 {
759 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSRegExp();
760 }
761
IsJSFunction()762 inline bool JSTaggedValue::IsJSFunction() const
763 {
764 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSFunction();
765 }
766
IsJSFunctionBase()767 inline bool JSTaggedValue::IsJSFunctionBase() const
768 {
769 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSFunctionBase();
770 }
771
IsBoundFunction()772 inline bool JSTaggedValue::IsBoundFunction() const
773 {
774 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJsBoundFunction();
775 }
776
IsJSIntlBoundFunction()777 inline bool JSTaggedValue::IsJSIntlBoundFunction() const
778 {
779 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSIntlBoundFunction();
780 }
781
IsProxyRevocFunction()782 inline bool JSTaggedValue::IsProxyRevocFunction() const
783 {
784 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSProxyRevocFunction();
785 }
786
IsJSAsyncFunction()787 inline bool JSTaggedValue::IsJSAsyncFunction() const
788 {
789 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAsyncFunction();
790 }
791
IsJSAsyncAwaitStatusFunction()792 inline bool JSTaggedValue::IsJSAsyncAwaitStatusFunction() const
793 {
794 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAsyncAwaitStatusFunction();
795 }
796
IsJSPrimitiveRef()797 inline bool JSTaggedValue::IsJSPrimitiveRef() const
798 {
799 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJsPrimitiveRef();
800 }
801
IsJSPrimitive()802 inline bool JSTaggedValue::IsJSPrimitive() const
803 {
804 return IsNumber() || IsStringOrSymbol() || IsBoolean();
805 }
806
IsAccessorData()807 inline bool JSTaggedValue::IsAccessorData() const
808 {
809 return IsHeapObject() && GetTaggedObject()->GetClass()->IsAccessorData();
810 }
811
IsInternalAccessor()812 inline bool JSTaggedValue::IsInternalAccessor() const
813 {
814 return IsHeapObject() && GetTaggedObject()->GetClass()->IsInternalAccessor();
815 }
816
IsAccessor()817 inline bool JSTaggedValue::IsAccessor() const
818 {
819 if (IsHeapObject()) {
820 auto *jshcalss = GetTaggedObject()->GetClass();
821 return jshcalss->IsAccessorData() || jshcalss->IsInternalAccessor();
822 }
823
824 return false;
825 }
826
IsPrototypeHandler()827 inline bool JSTaggedValue::IsPrototypeHandler() const
828 {
829 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPrototypeHandler();
830 }
831
IsTransitionHandler()832 inline bool JSTaggedValue::IsTransitionHandler() const
833 {
834 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTransitionHandler();
835 }
836
IsPropertyBox()837 inline bool JSTaggedValue::IsPropertyBox() const
838 {
839 return IsHeapObject() && GetTaggedObject()->GetClass()->IsPropertyBox();
840 }
841
IsProtoChangeDetails()842 inline bool JSTaggedValue::IsProtoChangeDetails() const
843 {
844 return IsHeapObject() && GetTaggedObject()->GetClass()->IsProtoChangeDetails();
845 }
IsProtoChangeMarker()846 inline bool JSTaggedValue::IsProtoChangeMarker() const
847 {
848 return IsHeapObject() && GetTaggedObject()->GetClass()->IsProtoChangeMarker();
849 }
850
IsJSGlobalEnv()851 inline bool JSTaggedValue::IsJSGlobalEnv() const
852 {
853 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJsGlobalEnv();
854 }
855
IsForinIterator()856 inline bool JSTaggedValue::IsForinIterator() const
857 {
858 return IsHeapObject() && GetTaggedObject()->GetClass()->IsForinIterator();
859 }
860
IsJSSetIterator()861 inline bool JSTaggedValue::IsJSSetIterator() const
862 {
863 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSSetIterator();
864 }
865
IsJSMapIterator()866 inline bool JSTaggedValue::IsJSMapIterator() const
867 {
868 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSMapIterator();
869 }
870
IsJSAPITreeMapIterator()871 inline bool JSTaggedValue::IsJSAPITreeMapIterator() const
872 {
873 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPITreeMapIterator();
874 }
875
IsJSAPITreeSetIterator()876 inline bool JSTaggedValue::IsJSAPITreeSetIterator() const
877 {
878 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPITreeSetIterator();
879 }
880
IsJSArrayIterator()881 inline bool JSTaggedValue::IsJSArrayIterator() const
882 {
883 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSArrayIterator();
884 }
885
IsJSAPIArrayListIterator()886 inline bool JSTaggedValue::IsJSAPIArrayListIterator() const
887 {
888 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSAPIArrayListIterator();
889 }
890
IsIterator()891 inline bool JSTaggedValue::IsIterator() const
892 {
893 return IsHeapObject() && GetTaggedObject()->GetClass()->IsIterator();
894 }
895
IsGeneratorFunction()896 inline bool JSTaggedValue::IsGeneratorFunction() const
897 {
898 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorFunction();
899 }
900
IsGeneratorObject()901 inline bool JSTaggedValue::IsGeneratorObject() const
902 {
903 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject();
904 }
905
IsGeneratorContext()906 inline bool JSTaggedValue::IsGeneratorContext() const
907 {
908 return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext();
909 }
910
IsAsyncFuncObject()911 inline bool JSTaggedValue::IsAsyncFuncObject() const
912 {
913 return IsHeapObject() && GetTaggedObject()->GetClass()->IsAsyncFuncObject();
914 }
915
IsDynClass()916 inline bool JSTaggedValue::IsDynClass() const
917 {
918 return IsJSHClass();
919 }
920
IsJSHClass()921 inline bool JSTaggedValue::IsJSHClass() const
922 {
923 return IsHeapObject() && GetTaggedObject()->GetClass()->IsHClass();
924 }
925
IsStringIterator()926 inline bool JSTaggedValue::IsStringIterator() const
927 {
928 return IsHeapObject() && GetTaggedObject()->GetClass()->IsStringIterator();
929 }
930
IsArrayBuffer()931 inline bool JSTaggedValue::IsArrayBuffer() const
932 {
933 return IsHeapObject() && GetTaggedObject()->GetClass()->IsArrayBuffer();
934 }
935
IsDataView()936 inline bool JSTaggedValue::IsDataView() const
937 {
938 return IsHeapObject() && GetTaggedObject()->GetClass()->IsDataView();
939 }
940
IsTemplateMap()941 inline bool JSTaggedValue::IsTemplateMap() const
942 {
943 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTemplateMap();
944 }
945
IsJSGlobalObject()946 inline bool JSTaggedValue::IsJSGlobalObject() const
947 {
948 return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSGlobalObject();
949 }
950
IsMachineCodeObject()951 inline bool JSTaggedValue::IsMachineCodeObject() const
952 {
953 return IsHeapObject() && GetTaggedObject()->GetClass()->IsMachineCodeObject();
954 }
955
IsClassInfoExtractor()956 inline bool JSTaggedValue::IsClassInfoExtractor() const
957 {
958 return IsHeapObject() && GetTaggedObject()->GetClass()->IsClassInfoExtractor();
959 }
960
IsTSObjectType()961 inline bool JSTaggedValue::IsTSObjectType() const
962 {
963 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSObjectType();
964 }
965
IsTSClassType()966 inline bool JSTaggedValue::IsTSClassType() const
967 {
968 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSClassType();
969 }
970
IsTSInterfaceType()971 inline bool JSTaggedValue::IsTSInterfaceType() const
972 {
973 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSInterfaceType();
974 }
975
IsTSUnionType()976 inline bool JSTaggedValue::IsTSUnionType() const
977 {
978 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSUnionType();
979 }
980
IsTSImportType()981 inline bool JSTaggedValue::IsTSImportType() const
982 {
983 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSImportType();
984 }
985
IsTSClassInstanceType()986 inline bool JSTaggedValue::IsTSClassInstanceType() const
987 {
988 return IsHeapObject() && GetTaggedObject()->GetClass()->IsTSClassInstanceType();
989 }
990
ExtractNumber()991 inline double JSTaggedValue::ExtractNumber() const
992 {
993 ASSERT(IsNumber());
994 return GetNumber();
995 }
996
997 // 9.4.2.4 ArraySetLength 3 to 7
ToArrayLength(JSThread * thread,const JSHandle<JSTaggedValue> & tagged,uint32_t * output)998 inline bool JSTaggedValue::ToArrayLength(JSThread *thread, const JSHandle<JSTaggedValue> &tagged, uint32_t *output)
999 {
1000 // 3. Let newLen be ToUint32(Desc.[[Value]]).
1001 uint32_t newLen = ToUint32(thread, tagged);
1002 // 4. ReturnIfAbrupt(newLen).
1003 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1004
1005 // 5. Let numberLen be ToNumber(Desc.[[Value]]).
1006 JSTaggedNumber numberLen = ToNumber(thread, tagged);
1007 // 6. ReturnIfAbrupt(newLen).
1008 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1009
1010 // 7. If newLen != numberLen, throw a RangeError exception.
1011 if (JSTaggedNumber(newLen) != numberLen) {
1012 THROW_RANGE_ERROR_AND_RETURN(thread, "Not a valid array length", false);
1013 }
1014
1015 *output = newLen;
1016 return true;
1017 }
1018
GetArrayLength()1019 inline uint32_t JSTaggedValue::GetArrayLength() const
1020 {
1021 ASSERT(IsNumber());
1022 if (IsInt()) {
1023 return static_cast<uint32_t>(GetInt());
1024 }
1025 if (IsDouble()) {
1026 ASSERT(GetDouble() <= TaggedArray::MAX_ARRAY_INDEX);
1027 return static_cast<uint32_t>(GetDouble());
1028 }
1029 UNREACHABLE();
1030 }
1031
ToElementIndex(JSTaggedValue key,uint32_t * output)1032 inline bool JSTaggedValue::ToElementIndex(JSTaggedValue key, uint32_t *output)
1033 {
1034 if (key.IsInt()) {
1035 int index = key.GetInt();
1036 if (index >= 0) {
1037 *output = index;
1038 return true;
1039 }
1040 } else if (key.IsDouble()) {
1041 double d = key.GetDouble();
1042 uint32_t index = base::NumberHelper::DoubleToInt(d, base::INT32_BITS);
1043 if (d - static_cast<double>(index) == 0.0) {
1044 *output = index;
1045 return true;
1046 }
1047 } else if (key.IsString()) {
1048 return StringToElementIndex(key, output);
1049 }
1050 return false;
1051 }
1052
StringToElementIndex(JSTaggedValue key,uint32_t * output)1053 inline bool JSTaggedValue::StringToElementIndex(JSTaggedValue key, uint32_t *output)
1054 {
1055 ASSERT(key.IsString());
1056
1057 auto strObj = static_cast<EcmaString *>(key.GetTaggedObject());
1058 uint32_t len = strObj->GetLength();
1059 if (len == 0 || len > MAX_INDEX_LEN) { // NOLINTNEXTLINEreadability-magic-numbers)
1060 return false;
1061 }
1062 uint32_t c;
1063 if (strObj->IsUtf16()) {
1064 c = strObj->GetDataUtf16()[0]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1065 } else {
1066 c = strObj->GetDataUtf8()[0]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1067 }
1068 uint64_t n = 0;
1069 if (c >= '0' && c <= '9') {
1070 if (c == '0') {
1071 if (len != 1) {
1072 return false;
1073 }
1074 *output = 0;
1075 return true;
1076 }
1077
1078 n = c - '0';
1079 for (uint32_t i = 1; i < len; i++) {
1080 if (strObj->IsUtf16()) {
1081 c = strObj->GetDataUtf16()[i]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1082 } else {
1083 c = strObj->GetDataUtf8()[i]; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1084 }
1085 if (c < '0' || c > '9') {
1086 return false;
1087 }
1088 // NOLINTNEXTLINE(readability-magic-numbers)
1089 n = n * 10 + (c - '0'); // 10: decimal factor
1090 }
1091 if (n < JSObject::MAX_ELEMENT_INDEX) {
1092 *output = n;
1093 return true;
1094 }
1095 }
1096 return false;
1097 }
1098
GetKeyHashCode()1099 inline uint32_t JSTaggedValue::GetKeyHashCode() const
1100 {
1101 ASSERT(IsStringOrSymbol());
1102 if (IsString()) {
1103 return EcmaString::Cast(GetTaggedObject())->GetHashcode();
1104 }
1105
1106 return JSSymbol::Cast(GetTaggedObject())->GetHashField();
1107 }
1108 } // namespace panda::ecmascript
1109 #endif // ECMASCRIPT_TAGGED_VALUE__INL_H
1110