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/builtins/builtins_number.h" 17 18#include "ecmascript/js_function.h" 19#include "ecmascript/js_primitive_ref.h" 20#ifdef ARK_SUPPORT_INTL 21#include "ecmascript/js_number_format.h" 22#else 23#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL 24#include "ecmascript/intl/global_intl_helper.h" 25#endif 26#endif 27 28namespace panda::ecmascript::builtins { 29using NumberHelper = base::NumberHelper; 30 31JSTaggedValue BuiltinsNumber::NumberConstructor(EcmaRuntimeCallInfo *argv) 32{ 33 ASSERT(argv); 34 BUILTINS_API_TRACE(argv->GetThread(), Number, Constructor); 35 JSThread *thread = argv->GetThread(); 36 [[maybe_unused]] EcmaHandleScope handleScope(thread); 37 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 38 39 // 1. If value is present, then a , b , c. 40 // 2. Else Let n be +0. 41 JSTaggedNumber numberValue(0); 42 if (argv->GetArgsNumber() > 0) { 43 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 44 // a. Let prim be ? ToNumeric(value). 45 if (!value->IsNumber()) { 46 JSHandle<JSTaggedValue> numericVal = JSTaggedValue::ToNumeric(thread, value); 47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 48 // b. If Type(prim) is BigInt, let n be (ℝ(prim)). 49 if (numericVal->IsBigInt()) { 50 JSHandle<BigInt> bigNumericVal(numericVal); 51 numberValue = BigInt::BigIntToNumber(bigNumericVal); 52 } else { 53 // c. Otherwise, let n be prim. 54 numberValue = JSTaggedNumber(numericVal.GetTaggedValue()); 55 } 56 } else { 57 numberValue = JSTaggedNumber(value.GetTaggedValue()); 58 } 59 } 60 // 3. If NewTarget is undefined, return n. 61 if (newTarget->IsUndefined()) { 62 return numberValue; 63 } 64 // 4. Let O be OrdinaryCreateFromConstructor(NewTarget, "%NumberPrototype%", «[[NumberData]]» ). 65 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 66 JSHandle<JSObject> result = 67 thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(constructor), newTarget); 68 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 69 // 5. Set O.[[NumberData]] to n. 70 JSPrimitiveRef::Cast(*result)->SetValue(thread, numberValue); 71 // 6. Return O. 72 return result.GetTaggedValue(); 73} 74 75// 20.1.2.2 76JSTaggedValue BuiltinsNumber::IsFinite(EcmaRuntimeCallInfo *argv) 77{ 78 ASSERT(argv); 79 BUILTINS_API_TRACE(argv->GetThread(), Number, IsFinite); 80 JSTaggedValue msg = GetCallArg(argv, 0).GetTaggedValue(); 81 // 1. If Type(number) is not Number, return false 82 // 2. If number is NaN, +infinite, or -infinite, return false 83 if (NumberHelper::IsFinite(msg)) { 84 return GetTaggedBoolean(true); 85 } 86 return GetTaggedBoolean(false); 87} 88 89// 20.1.2.3 90JSTaggedValue BuiltinsNumber::IsInteger(EcmaRuntimeCallInfo *argv) 91{ 92 ASSERT(argv); 93 BUILTINS_API_TRACE(argv->GetThread(), Number, IsInteger); 94 JSThread *thread = argv->GetThread(); 95 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 96 bool result = false; 97 // 1. If Type(number) is not Number, return false. 98 // 2. If number is NaN, +infinite, or -infinite, return false 99 if (NumberHelper::IsFinite(msg.GetTaggedValue())) { 100 [[maybe_unused]] EcmaHandleScope handleScope(thread); 101 double value = JSTaggedNumber(msg.GetTaggedValue()).GetNumber(); 102 // 3. Let integer be ToInteger(number). 103 JSTaggedNumber number = JSTaggedValue::ToInteger(thread, msg); 104 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 105 // 4. If integer is not equal to number, return false. 106 // 5. Otherwise, return true. 107 result = (value == number.GetNumber()); 108 } 109 return GetTaggedBoolean(result); 110} 111 112// 20.1.2.4 113JSTaggedValue BuiltinsNumber::IsNaN(EcmaRuntimeCallInfo *argv) 114{ 115 ASSERT(argv); 116 BUILTINS_API_TRACE(argv->GetThread(), Number, IsNaN); 117 JSTaggedValue msg = GetCallArg(argv, 0).GetTaggedValue(); 118 // 1. If Type(number) is not Number, return false. 119 // 2. If number is NaN, return true. 120 if (NumberHelper::IsNaN(msg)) { 121 return GetTaggedBoolean(true); 122 } 123 // 3. Otherwise, return false. 124 return GetTaggedBoolean(false); 125} 126 127// 20.1.2.5 128JSTaggedValue BuiltinsNumber::IsSafeInteger(EcmaRuntimeCallInfo *argv) 129{ 130 ASSERT(argv); 131 BUILTINS_API_TRACE(argv->GetThread(), Number, IsSafeInteger); 132 JSThread *thread = argv->GetThread(); 133 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 134 bool result = false; 135 // 1. If Type(number) is not Number, return false. 136 // 2. If number is NaN, +infinite, or -infinite, return false 137 if (NumberHelper::IsFinite(msg.GetTaggedValue())) { 138 [[maybe_unused]] EcmaHandleScope handleScope(thread); 139 double value = JSTaggedNumber(msg.GetTaggedValue()).GetNumber(); 140 // 3. Let integer be ToInteger(number). 141 JSTaggedNumber number = JSTaggedValue::ToInteger(thread, msg); 142 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 143 // 4. If integer is not equal to number, return false. 144 // 5. If abs(integer) ≤ 253−1, return true. 145 result = (value == number.GetNumber()) && std::abs(value) <= base::MAX_SAFE_INTEGER; 146 } 147 return GetTaggedBoolean(result); 148} 149 150// 18.2.4 151// 20.1.2.12 152JSTaggedValue BuiltinsNumber::ParseFloat(EcmaRuntimeCallInfo *argv) 153{ 154 ASSERT(argv); 155 BUILTINS_API_TRACE(argv->GetThread(), Number, ParseFloat); 156 JSThread *thread = argv->GetThread(); 157 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 158 if (msg->IsUndefined()) { 159 return GetTaggedDouble(base::NAN_VALUE); 160 } 161 [[maybe_unused]] EcmaHandleScope handleScope(thread); 162 // 1. Let inputString be ToString(string). 163 JSHandle<EcmaString> numberString = JSTaggedValue::ToString(thread, msg); 164 // 2. ReturnIfAbrupt(inputString). 165 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 166 CVector<uint8_t> buf; 167 Span<const uint8_t> str = EcmaStringAccessor(numberString).ToUtf8Span(buf); 168 // 4. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral 169 // (see 7.1.3.1), return NaN. 170 if (NumberHelper::IsEmptyString(str.begin(), str.end())) { 171 return BuiltinsBase::GetTaggedDouble(base::NAN_VALUE); 172 } 173 double result = NumberHelper::StringToDouble(str.begin(), str.end(), 0, base::IGNORE_TRAILING); 174 return GetTaggedDouble(result); 175} 176 177// 18.2.5 178// 20.1.2.13 179JSTaggedValue BuiltinsNumber::ParseInt(EcmaRuntimeCallInfo *argv) 180{ 181 ASSERT(argv); 182 BUILTINS_API_TRACE(argv->GetThread(), Number, ParseInt); 183 JSThread *thread = argv->GetThread(); 184 [[maybe_unused]] EcmaHandleScope handleScope(thread); 185 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 186 JSHandle<JSTaggedValue> arg2 = GetCallArg(argv, 1); 187 int32_t radix = 0; 188 189 // 1. Let inputString be ToString(string). 190 JSHandle<EcmaString> numberString = JSTaggedValue::ToString(thread, msg); 191 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 192 if (!arg2->IsUndefined()) { 193 // 7. Let R = ToInt32(radix). 194 radix = JSTaggedValue::ToInt32(thread, arg2); 195 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 196 } 197 198 return NumberHelper::StringToNumber(*numberString, radix); 199} 200 201// prototype 202// 20.1.3.2 203JSTaggedValue BuiltinsNumber::ToExponential(EcmaRuntimeCallInfo *argv) 204{ 205 ASSERT(argv); 206 JSThread *thread = argv->GetThread(); 207 BUILTINS_API_TRACE(thread, Number, ToExponential); 208 [[maybe_unused]] EcmaHandleScope handleScope(thread); 209 // 1. Let x be ? thisNumberValue(this value). 210 JSTaggedNumber value = ThisNumberValue(thread, argv); 211 // 2. ReturnIfAbrupt(x). 212 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 213 214 // 3. Let f be ToInteger(fractionDigits). 215 JSHandle<JSTaggedValue> digits = GetCallArg(argv, 0); 216 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digits); 217 // 5. ReturnIfAbrupt(f). 218 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 219 220 double values = value.GetNumber(); 221 // 6. If x is NaN, return the String "NaN". 222 if (std::isnan(values)) { 223 return GetTaggedString(thread, "NaN"); 224 } 225 // 8. If x < 0, then 226 // a. Let s be "-". 227 // b. Let x = –x. 228 // 9. If x = +infinity, then 229 // a. Return the concatenation of the Strings s and "Infinity". 230 if (!std::isfinite(values)) { 231 if (values < 0) { 232 return GetTaggedString(thread, "-Infinity"); 233 } 234 return GetTaggedString(thread, "Infinity"); 235 } 236 237 // 4. Assert: f is 0, when fractionDigits is undefined. 238 // 10. If f < 0 or f > 20, throw a RangeError exception 239 double fraction = digitInt.GetNumber(); 240 if (digits->IsUndefined()) { 241 fraction = 0; 242 } else { 243 if (fraction < base::MIN_FRACTION || fraction > base::MAX_FRACTION) { 244 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception()); 245 } 246 fraction++; 247 } 248 return NumberHelper::DoubleToExponential(thread, values, static_cast<int>(fraction)); 249} 250 251// 20.1.3.3 252JSTaggedValue BuiltinsNumber::ToFixed(EcmaRuntimeCallInfo *argv) 253{ 254 ASSERT(argv); 255 JSThread *thread = argv->GetThread(); 256 BUILTINS_API_TRACE(thread, Number, ToFixed); 257 [[maybe_unused]] EcmaHandleScope handleScope(thread); 258 // 1. Let x be ? thisNumberValue(this value). 259 JSTaggedNumber value = ThisNumberValue(thread, argv); 260 // 2. ReturnIfAbrupt(x). 261 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 262 // 3. Let f be ToInteger(fractionDigits). (If fractionDigits is undefined, this step produces the value 0). 263 JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0); 264 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv); 265 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 266 if (digitArgv->IsUndefined()) { 267 digitInt = JSTaggedNumber(0); 268 } 269 // 4. ReturnIfAbrupt(f). 270 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 271 double digit = digitInt.GetNumber(); 272 if (digit < base::MIN_FRACTION || digit > base::MAX_FRACTION) { 273 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 0 to 100", JSTaggedValue::Exception()); 274 } 275 276 // 6. If x is NaN, return the String "NaN". 277 double valueNumber = value.GetNumber(); 278 if (std::isnan(valueNumber)) { 279 const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 280 return globalConst->GetNanCapitalString(); 281 } 282 if (!std::isfinite(valueNumber)) { 283 if (valueNumber < 0) { 284 return GetTaggedString(thread, "-Infinity"); 285 } 286 return GetTaggedString(thread, "Infinity"); 287 } 288 // 9. If x 1021, then 289 // a. Let m = ToString(x). 290 const double FIRST_NO_FIXED = 1e21; 291 if (std::abs(valueNumber) >= FIRST_NO_FIXED) { 292 return value.ToString(thread).GetTaggedValue(); 293 } 294 return NumberHelper::DoubleToFixedString(thread, valueNumber, static_cast<int>(digit)); 295} 296 297// 20.1.3.4 298JSTaggedValue BuiltinsNumber::ToLocaleString(EcmaRuntimeCallInfo *argv) 299{ 300 ASSERT(argv); 301 JSThread *thread = argv->GetThread(); 302 BUILTINS_API_TRACE(thread, Number, ToLocaleString); 303 [[maybe_unused]] EcmaHandleScope handleScope(thread); 304 // 1. Let x be ? thisNumberValue(this value). 305 [[maybe_unused]] JSHandle<JSTaggedValue> x(thread, ThisNumberValue(thread, argv)); 306 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 307 308 JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 309 JSHandle<JSTaggedValue> options = GetCallArg(argv, 1); 310 [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined(); 311#ifdef ARK_SUPPORT_INTL 312 if (cacheable) { 313 auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales); 314 if (numberFormatter != nullptr) { 315 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue()); 316 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 317 return result.GetTaggedValue(); 318 } 319 } 320 // 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »). 321 EcmaVM *ecmaVm = thread->GetEcmaVM(); 322 JSHandle<JSFunction> ctor(ecmaVm->GetGlobalEnv()->GetNumberFormatFunction()); 323 ObjectFactory *factory = ecmaVm->GetFactory(); 324 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(ctor); 325 JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj); 326 JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options, cacheable); 327 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 328 if (cacheable) { 329 auto numberFormatter = JSNumberFormat::GetCachedIcuNumberFormatter(thread, locales); 330 ASSERT(numberFormatter != nullptr); 331 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormatter, x.GetTaggedValue()); 332 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 333 return result.GetTaggedValue(); 334 } 335 336 // Return ? FormatNumeric(numberFormat, x). 337 JSHandle<JSTaggedValue> result = JSNumberFormat::FormatNumeric(thread, numberFormat, x.GetTaggedValue()); 338 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 339 return result.GetTaggedValue(); 340#else 341#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL 342 ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare"); 343#else 344 intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::NumberFormatter); 345 auto numberFormatter = gh.GetGlobalObject<intl::GlobalNumberFormat>(thread, 346 locales, options, intl::GlobalFormatterType::NumberFormatter, cacheable); 347 if (numberFormatter == nullptr) { 348 LOG_ECMA(ERROR) << "BuiltinsNumber:numberFormatter is nullptr"; 349 } 350 ASSERT(numberFormatter != nullptr); 351 std::string result = numberFormatter->Format(x->GetDouble()); 352 EcmaVM *ecmaVm = thread->GetEcmaVM(); 353 ObjectFactory *factory = ecmaVm->GetFactory(); 354 JSHandle returnValue = factory->NewFromStdString(result); 355 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 356 return returnValue.GetTaggedValue(); 357#endif 358#endif 359} 360 361// 20.1.3.5 362JSTaggedValue BuiltinsNumber::ToPrecision(EcmaRuntimeCallInfo *argv) 363{ 364 ASSERT(argv); 365 JSThread *thread = argv->GetThread(); 366 BUILTINS_API_TRACE(thread, Number, ToPrecision); 367 [[maybe_unused]] EcmaHandleScope handleScope(thread); 368 // 1. Let x be ? thisNumberValue(this value). 369 JSTaggedNumber value = ThisNumberValue(thread, argv); 370 // 2. ReturnIfAbrupt(x). 371 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 372 373 // 3. If precision is undefined, return ToString(x). 374 JSHandle<JSTaggedValue> digitArgv = GetCallArg(argv, 0); 375 if (digitArgv->IsUndefined()) { 376 return value.ToString(thread).GetTaggedValue(); 377 } 378 // 4. Let p be ToInteger(precision). 379 JSTaggedNumber digitInt = JSTaggedValue::ToInteger(thread, digitArgv); 380 // 5. ReturnIfAbrupt(p). 381 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 382 383 // 6. If x is NaN, return the String "NaN". 384 double valueNumber = value.GetNumber(); 385 if (std::isnan(valueNumber)) { 386 return GetTaggedString(thread, "NaN"); 387 } 388 // 9. If x = +infinity, then 389 // a. Return the String that is the concatenation of s and "Infinity". 390 if (!std::isfinite(valueNumber)) { 391 if (valueNumber < 0) { 392 return GetTaggedString(thread, "-Infinity"); 393 } 394 return GetTaggedString(thread, "Infinity"); 395 } 396 397 // If p < 1 or p > 21, throw a RangeError exception 398 double digit = digitInt.GetNumber(); 399 if (digit < base::MIN_FRACTION + 1 || digit > base::MAX_FRACTION) { 400 THROW_RANGE_ERROR_AND_RETURN(thread, "fraction must be 1 to 100", JSTaggedValue::Exception()); 401 } 402 return NumberHelper::DoubleToPrecisionString(thread, valueNumber, static_cast<int>(digit)); 403} 404 405// 20.1.3.6 406JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv) 407{ 408 ASSERT(argv); 409 JSThread *thread = argv->GetThread(); 410 BUILTINS_API_TRACE(thread, Number, ToString); 411 // NOTE: There is no heap alloc in fast path, so delay the scope. 412 413 // 1. Let x be ? thisNumberValue(this value). 414 JSTaggedNumber value = ThisNumberValue(thread, argv); 415 // 2. ReturnIfAbrupt(x). 416 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 417 418 // 3. If radix is not present, let radixNumber be 10. 419 // 4. Else if radix is undefined, let radixNumber be 10. 420 double radix = base::DECIMAL; 421 JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0); 422 // 5. Else let radixNumber be ToInteger(radix). 423 if (radixValue->IsInt()) { 424 radix = radixValue->GetInt(); 425 } else if (!radixValue->IsUndefined()) { 426 JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue); 427 // 6. ReturnIfAbrupt(x). 428 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 429 radix = radixNumber.GetNumber(); 430 } 431 432 // 7. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. 433 if (radix < base::MIN_RADIX || radix > base::MAX_RADIX) { 434 THROW_RANGE_ERROR_AND_RETURN(thread, "radix must be 2 to 36", JSTaggedValue::Exception()); 435 } 436 // 8. If radixNumber = 10, return ToString(x). 437 if (radix == base::DECIMAL) { 438 JSHandle<NumberToStringResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetNumberToStringResultCache()); 439 int entry = cacheTable->GetNumberHash(value); 440 JSTaggedValue cacheResult = cacheTable->FindCachedResult(entry, value); 441 if (cacheResult != JSTaggedValue::Undefined()) { 442 return cacheResult; 443 } 444 // NOTE: There is no heap alloc before here, so delay the scope to here. 445 [[maybe_unused]] EcmaHandleScope handleScope(thread); 446 JSHandle<EcmaString> resultJSHandle = value.ToString(thread); 447 cacheTable->SetCachedResult(thread, entry, value, resultJSHandle); 448 return resultJSHandle.GetTaggedValue(); 449 } 450 // NOTE: There is no heap alloc before here, so delay the scope to here. 451 [[maybe_unused]] EcmaHandleScope handleScope(thread); 452 if (value.IsInt()) { 453 return NumberHelper::Int32ToString(thread, value.GetInt(), radix); 454 } 455 456 double valueNumber = value.GetNumber(); 457 // If x is NaN, return the String "NaN". 458 if (std::isnan(valueNumber)) { 459 return GetTaggedString(thread, "NaN"); 460 } 461 // If x = +infinity, then 462 // Return the String that is the concatenation of s and "Infinity". 463 if (!std::isfinite(valueNumber)) { 464 if (valueNumber < 0) { 465 return GetTaggedString(thread, "-Infinity"); 466 } 467 return GetTaggedString(thread, "Infinity"); 468 } 469 return NumberHelper::DoubleToString(thread, valueNumber, static_cast<int>(radix)); 470} 471 472// 20.1.3.7 473JSTaggedValue BuiltinsNumber::ValueOf(EcmaRuntimeCallInfo *argv) 474{ 475 ASSERT(argv); 476 JSThread *thread = argv->GetThread(); 477 BUILTINS_API_TRACE(thread, Number, ValueOf); 478 // 1. Let x be ? thisNumberValue(this value). 479 JSTaggedValue x = ThisNumberValue(thread, argv); 480 481 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 482 return x; 483} 484 485JSTaggedNumber BuiltinsNumber::ThisNumberValue(JSThread *thread, EcmaRuntimeCallInfo *argv) 486{ 487 BUILTINS_API_TRACE(thread, Number, ThisNumberValue); 488 JSHandle<JSTaggedValue> value = GetThis(argv); 489 if (value->IsNumber()) { 490 return JSTaggedNumber(value.GetTaggedValue()); 491 } 492 if (value->IsJSPrimitiveRef()) { 493 JSTaggedValue primitive = JSPrimitiveRef::Cast(value->GetTaggedObject())->GetValue(); 494 if (primitive.IsNumber()) { 495 return JSTaggedNumber(primitive); 496 } 497 } 498 [[maybe_unused]] EcmaHandleScope handleScope(thread); 499 THROW_TYPE_ERROR_AND_RETURN(thread, "not number type", JSTaggedNumber::Exception()); 500} 501 502JSTaggedValue NumberToStringResultCache::CreateCacheTable(const JSThread *thread) 503{ 504 int length = INITIAL_CACHE_NUMBER * ENTRY_SIZE; 505 auto table = static_cast<NumberToStringResultCache*>( 506 *thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length, JSTaggedValue::Undefined())); 507 return JSTaggedValue(table); 508} 509 510JSTaggedValue NumberToStringResultCache::FindCachedResult(int entry, JSTaggedValue &target) 511{ 512 uint32_t index = static_cast<uint32_t>(entry * ENTRY_SIZE); 513 JSTaggedValue entryNumber = Get(index + NUMBER_INDEX); 514 if (entryNumber == target) { 515 return Get(index + RESULT_INDEX); 516 } 517 return JSTaggedValue::Undefined(); 518} 519 520void NumberToStringResultCache::SetCachedResult(const JSThread *thread, int entry, JSTaggedValue &number, 521 JSHandle<EcmaString> &result) 522{ 523 uint32_t index = static_cast<uint32_t>(entry * ENTRY_SIZE); 524 Set(thread, index + NUMBER_INDEX, number); 525 Set(thread, index + RESULT_INDEX, result.GetTaggedValue()); 526} 527} // namespace panda::ecmascript::builtins 528