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#include "ecmascript/builtins/builtins_math.h" 17#include <random> 18#include <sys/time.h> 19#include "ecmascript/js_tagged_value-inl.h" 20 21namespace panda::ecmascript::builtins { 22using NumberHelper = base::NumberHelper; 23using RandomGenerator = base::RandomGenerator; 24 25// 20.2.2.1 26JSTaggedValue BuiltinsMath::Abs(EcmaRuntimeCallInfo *argv) 27{ 28 ASSERT(argv); 29 BUILTINS_API_TRACE(argv->GetThread(), Math, Abs); 30 JSThread *thread = argv->GetThread(); 31 [[maybe_unused]] EcmaHandleScope handleScope(thread); 32 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 33 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 34 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 35 if (numberValue.IsDouble()) { 36 // if number_value is double,NaN,Undefine, deal in this case 37 // if number_value is a String ,which can change to double. e.g."100",deal in this case 38 return GetTaggedDouble(std::fabs(numberValue.GetDouble())); 39 } 40 // if number_value is int,boolean,null, deal in this case 41 int value = numberValue.GetInt(); 42 if (value == INT_MIN) { 43 return GetTaggedDouble(-static_cast<int64_t>(INT_MIN)); 44 } 45 return GetTaggedInt(std::abs(value)); 46} 47 48// 20.2.2.2 49JSTaggedValue BuiltinsMath::Acos(EcmaRuntimeCallInfo *argv) 50{ 51 ASSERT(argv); 52 BUILTINS_API_TRACE(argv->GetThread(), Math, Acos); 53 JSThread *thread = argv->GetThread(); 54 [[maybe_unused]] EcmaHandleScope handleScope(thread); 55 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 56 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 57 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 58 double value = numberValue.GetNumber(); 59 double result = base::NAN_VALUE; 60 // value == -NaN , <-1 or > 1,result is NaN 61 if (!std::isnan(std::abs(value)) && value <= 1 && value >= -1) { 62 result = std::acos(value); 63 } 64 return GetTaggedDouble(result); 65} 66 67// 20.2.2.3 68JSTaggedValue BuiltinsMath::Acosh(EcmaRuntimeCallInfo *argv) 69{ 70 ASSERT(argv); 71 BUILTINS_API_TRACE(argv->GetThread(), Math, Acosh); 72 JSThread *thread = argv->GetThread(); 73 [[maybe_unused]] EcmaHandleScope handleScope(thread); 74 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 75 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 76 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 77 double value = numberValue.GetNumber(); 78 double result = base::NAN_VALUE; 79 if (value >= 1) { 80 result = std::acosh(value); 81 } 82 return GetTaggedDouble(result); 83} 84 85// 20.2.2.4 86JSTaggedValue BuiltinsMath::Asin(EcmaRuntimeCallInfo *argv) 87{ 88 ASSERT(argv); 89 BUILTINS_API_TRACE(argv->GetThread(), Math, Asin); 90 JSThread *thread = argv->GetThread(); 91 [[maybe_unused]] EcmaHandleScope handleScope(thread); 92 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 93 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 94 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 95 double value = numberValue.GetNumber(); 96 double result = base::NAN_VALUE; 97 if (value >= -1 && value <= 1) { 98 result = std::asin(value); 99 } 100 return GetTaggedDouble(result); 101} 102 103// 20.2.2.5 104JSTaggedValue BuiltinsMath::Asinh(EcmaRuntimeCallInfo *argv) 105{ 106 ASSERT(argv); 107 BUILTINS_API_TRACE(argv->GetThread(), Math, Asinh); 108 JSThread *thread = argv->GetThread(); 109 [[maybe_unused]] EcmaHandleScope handleScope(thread); 110 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 111 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 112 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 113 double value = numberValue.GetNumber(); 114 double result = base::NAN_VALUE; 115 // value == -NaN, NaN, result is NaN 116 if (!std::isnan(std::abs(value))) { 117 result = base::MathHelper::Asinh(value); 118 } 119 return GetTaggedDouble(result); 120} 121 122// 20.2.2.6 123JSTaggedValue BuiltinsMath::Atan(EcmaRuntimeCallInfo *argv) 124{ 125 ASSERT(argv); 126 BUILTINS_API_TRACE(argv->GetThread(), Math, Atan); 127 JSThread *thread = argv->GetThread(); 128 [[maybe_unused]] EcmaHandleScope handleScope(thread); 129 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 130 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 131 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 132 double value = numberValue.GetNumber(); 133 double result = base::NAN_VALUE; 134 // value == -NaN, NaN, result is NaN 135 if (!std::isnan(std::abs(value))) { 136 result = std::atan(value); 137 } 138 return GetTaggedDouble(result); 139} 140 141// 20.2.2.7 142JSTaggedValue BuiltinsMath::Atanh(EcmaRuntimeCallInfo *argv) 143{ 144 ASSERT(argv); 145 BUILTINS_API_TRACE(argv->GetThread(), Math, Atanh); 146 JSThread *thread = argv->GetThread(); 147 [[maybe_unused]] EcmaHandleScope handleScope(thread); 148 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 149 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 150 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 151 double value = numberValue.GetNumber(); 152 double result = base::NAN_VALUE; 153 if (value >= -1 && value <= 1) { 154 result = base::MathHelper::Atanh(value); 155 } 156 return GetTaggedDouble(result); 157} 158 159// 20.2.2.8 160JSTaggedValue BuiltinsMath::Atan2(EcmaRuntimeCallInfo *argv) 161{ 162 ASSERT(argv); 163 BUILTINS_API_TRACE(argv->GetThread(), Math, Atan2); 164 JSThread *thread = argv->GetThread(); 165 [[maybe_unused]] EcmaHandleScope handleScope(thread); 166 JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 0); 167 JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 1); 168 double result = base::NAN_VALUE; 169 JSTaggedNumber numberValueY = JSTaggedValue::ToNumber(thread, msgY); 170 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 171 JSTaggedNumber numberValueX = JSTaggedValue::ToNumber(thread, msgX); 172 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 173 double valueY = numberValueY.GetNumber(); 174 double valueX = numberValueX.GetNumber(); 175 // y = +0 and x > +0, return +0 176 // y = -0 and x > +0, return -0 177 if (valueY == 0 && valueX > 0) { 178 result = valueY; 179 } else if (std::isfinite(valueY) && valueX == std::numeric_limits<double>::infinity()) { 180 // y < 0 and y is finite and x is POSITIVE_INFINITY,return -0 181 // y >= 0 and y is finite and x is POSITIVE_INFINITY,return +0 182 result = valueY >= 0 ? 0 : -0.0; 183 } else if (!std::isnan(std::abs(valueY)) && !std::isnan(std::abs(valueX))) { 184 // If either x or y is NaN, the result is NaN 185 result = std::atan2(valueY, valueX); 186 } 187 return GetTaggedDouble(result); 188} 189 190// 20.2.2.9 191JSTaggedValue BuiltinsMath::Cbrt(EcmaRuntimeCallInfo *argv) 192{ 193 ASSERT(argv); 194 BUILTINS_API_TRACE(argv->GetThread(), Math, Cbrt); 195 JSThread *thread = argv->GetThread(); 196 [[maybe_unused]] EcmaHandleScope handleScope(thread); 197 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 198 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 199 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 200 double value = numberValue.GetNumber(); 201 double result = base::NAN_VALUE; 202 // if value == -NaN, NaN, result is NaN 203 if (!std::isnan(std::abs(value))) { 204 result = std::cbrt(value); 205 } 206 return GetTaggedDouble(result); 207} 208 209// 20.2.2.10 210JSTaggedValue BuiltinsMath::Ceil(EcmaRuntimeCallInfo *argv) 211{ 212 ASSERT(argv); 213 BUILTINS_API_TRACE(argv->GetThread(), Math, Ceil); 214 JSThread *thread = argv->GetThread(); 215 [[maybe_unused]] EcmaHandleScope handleScope(thread); 216 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 217 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 218 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 219 double value = numberValue.GetNumber(); 220 double result = base::NAN_VALUE; 221 // If value is NaN or -NaN, +infinite, -infinite,return value 222 if (!std::isfinite(value)) { 223 // if value is -NaN , return NaN, else return value 224 if (!std::isnan(std::abs(value))) { 225 result = value; 226 } 227 } else { 228 result = std::ceil(value); 229 } 230 return GetTaggedDouble(result); 231} 232 233// 20.2.2.11 234JSTaggedValue BuiltinsMath::Clz32(EcmaRuntimeCallInfo *argv) 235{ 236 ASSERT(argv); 237 BUILTINS_API_TRACE(argv->GetThread(), Math, Clz32); 238 JSThread *thread = argv->GetThread(); 239 [[maybe_unused]] EcmaHandleScope handleScope(thread); 240 constexpr int defaultValue = 32; 241 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 242 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 243 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 244 double value = numberValue.GetNumber(); 245 auto tmpValue = std::abs(value); 246 auto result = numberValue.ToUint32(); 247 if (!std::isfinite(tmpValue) || tmpValue == 0 || result == 0) { 248 // If value is NaN or -NaN, +infinite, -infinite, 0,return 32 249 return GetTaggedInt(defaultValue); 250 } 251 return GetTaggedInt(__builtin_clz(result)); 252} 253 254// 20.2.2.12 255JSTaggedValue BuiltinsMath::Cos(EcmaRuntimeCallInfo *argv) 256{ 257 ASSERT(argv); 258 BUILTINS_API_TRACE(argv->GetThread(), Math, Cos); 259 JSThread *thread = argv->GetThread(); 260 [[maybe_unused]] EcmaHandleScope handleScope(thread); 261 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 262 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 263 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 264 double value = numberValue.GetNumber(); 265 double result = base::NAN_VALUE; 266 // If value is NaN or -NaN, +infinite, -infinite, result is NaN 267 if (std::isfinite(std::abs(value))) { 268 result = std::cos(value); 269 } 270 return GetTaggedDouble(result); 271} 272 273// 20.2.2.13 274JSTaggedValue BuiltinsMath::Cosh(EcmaRuntimeCallInfo *argv) 275{ 276 ASSERT(argv); 277 BUILTINS_API_TRACE(argv->GetThread(), Math, Cosh); 278 JSThread *thread = argv->GetThread(); 279 [[maybe_unused]] EcmaHandleScope handleScope(thread); 280 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 281 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 282 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 283 double value = numberValue.GetNumber(); 284 double result = base::NAN_VALUE; 285 // if value is NaN or -NaN, result is NaN 286 if (!std::isnan(std::abs(value))) { 287 result = std::cosh(value); 288 } 289 return GetTaggedDouble(result); 290} 291 292// 20.2.2.14 293JSTaggedValue BuiltinsMath::Exp(EcmaRuntimeCallInfo *argv) 294{ 295 ASSERT(argv); 296 BUILTINS_API_TRACE(argv->GetThread(), Math, Exp); 297 JSThread *thread = argv->GetThread(); 298 [[maybe_unused]] EcmaHandleScope handleScope(thread); 299 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 300 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 301 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 302 double value = numberValue.GetNumber(); 303 double result = base::NAN_VALUE; 304 // if value is NaN or -NaN, result is NaN 305 if (!std::isnan(std::abs(value))) { 306 result = std::exp(value); 307 } 308 return GetTaggedDouble(result); 309} 310 311// 20.2.2.15 312JSTaggedValue BuiltinsMath::Expm1(EcmaRuntimeCallInfo *argv) 313{ 314 ASSERT(argv); 315 BUILTINS_API_TRACE(argv->GetThread(), Math, Expm1); 316 JSThread *thread = argv->GetThread(); 317 [[maybe_unused]] EcmaHandleScope handleScope(thread); 318 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 319 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 320 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 321 double value = numberValue.GetNumber(); 322 double result = base::NAN_VALUE; 323 // if value is NaN or -NaN, result is NaN 324 if (!std::isnan(std::abs(value))) { 325 result = std::expm1(value); 326 } 327 return GetTaggedDouble(result); 328} 329 330// 20.2.2.16 331JSTaggedValue BuiltinsMath::Floor(EcmaRuntimeCallInfo *argv) 332{ 333 ASSERT(argv); 334 BUILTINS_API_TRACE(argv->GetThread(), Math, Floor); 335 JSThread *thread = argv->GetThread(); 336 [[maybe_unused]] EcmaHandleScope handleScope(thread); 337 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 338 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 339 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 340 double value = numberValue.GetNumber(); 341 double result = base::NAN_VALUE; 342 // If value is NaN or -NaN, +infinite, -infinite, +0, -0, return value 343 if (!std::isfinite(value) || value == 0) { 344 // If value is -NaN, return NaN, else return value 345 if (!std::isnan(std::abs(value))) { 346 result = value; 347 } 348 } else if (value > 0 && value < 1) { 349 // If x is greater than 0 but less than 1, the result is +0 350 result = 0; 351 } else { 352 result = std::floor(value); 353 } 354 return GetTaggedDouble(result); 355} 356 357// 20.2.2.17 358JSTaggedValue BuiltinsMath::Fround(EcmaRuntimeCallInfo *argv) 359{ 360 ASSERT(argv); 361 BUILTINS_API_TRACE(argv->GetThread(), Math, Fround); 362 JSThread *thread = argv->GetThread(); 363 [[maybe_unused]] EcmaHandleScope handleScope(thread); 364 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 365 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 366 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 367 double value = numberValue.GetNumber(); 368 double result; 369 if (std::isnan(std::abs(value))) { 370 // If result is NaN or -NaN, the result is NaN 371 result = base::NAN_VALUE; 372 } else { 373 result = static_cast<float>(value); 374 } 375 return GetTaggedDouble(result); 376} 377 378// 20.2.2.18 379JSTaggedValue BuiltinsMath::Hypot(EcmaRuntimeCallInfo *argv) 380{ 381 ASSERT(argv); 382 BUILTINS_API_TRACE(argv->GetThread(), Math, Hypot); 383 JSThread *thread = argv->GetThread(); 384 [[maybe_unused]] EcmaHandleScope handleScope(thread); 385 double result = 0; 386 double value = 0; 387 uint32_t argLen = argv->GetArgsNumber(); 388 auto numberValue = JSTaggedNumber(0); 389 for (uint32_t i = 0; i < argLen; i++) { 390 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i); 391 numberValue = JSTaggedValue::ToNumber(thread, msg); 392 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 393 value = numberValue.GetNumber(); 394 result = std::hypot(result, value); 395 } 396 return GetTaggedDouble(result); 397} 398 399// 20.2.2.19 400JSTaggedValue BuiltinsMath::Imul(EcmaRuntimeCallInfo *argv) 401{ 402 ASSERT(argv); 403 BUILTINS_API_TRACE(argv->GetThread(), Math, Imul); 404 JSThread *thread = argv->GetThread(); 405 [[maybe_unused]] EcmaHandleScope handleScope(thread); 406 JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 0); 407 JSHandle<JSTaggedValue> msg2 = GetCallArg(argv, 1); 408 JSTaggedNumber numberValue1 = JSTaggedValue::ToNumber(thread, msg1); 409 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 410 JSTaggedNumber numberValue2 = JSTaggedValue::ToNumber(thread, msg2); 411 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 412 auto value1 = numberValue1.GetNumber(); 413 auto value2 = numberValue2.GetNumber(); 414 if (!std::isfinite(value1) || !std::isfinite(value2)) { 415 // If value is NaN or -NaN, +infinite, -infinite 416 return GetTaggedInt(0); 417 } 418 value1 = numberValue1.ToInt32(); 419 value2 = numberValue2.ToInt32(); 420 // purposely ignoring overflow 421 auto result = static_cast<int32_t>(static_cast<int64_t>(value1) * static_cast<int64_t>(value2)); 422 return GetTaggedInt(result); 423} 424 425// 20.2.2.20 426JSTaggedValue BuiltinsMath::Log(EcmaRuntimeCallInfo *argv) 427{ 428 ASSERT(argv); 429 BUILTINS_API_TRACE(argv->GetThread(), Math, Log); 430 JSThread *thread = argv->GetThread(); 431 [[maybe_unused]] EcmaHandleScope handleScope(thread); 432 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 433 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 434 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 435 double value = numberValue.GetNumber(); 436 double result = base::NAN_VALUE; 437 // If value is NaN , -NaN , or < 0,result is NaN 438 if (!std::isnan(std::abs(value)) && value >= 0) { 439 result = std::log(value); 440 } 441 return GetTaggedDouble(result); 442} 443 444// 20.2.2.21 445JSTaggedValue BuiltinsMath::Log1p(EcmaRuntimeCallInfo *argv) 446{ 447 ASSERT(argv); 448 BUILTINS_API_TRACE(argv->GetThread(), Math, Log1p); 449 JSThread *thread = argv->GetThread(); 450 [[maybe_unused]] EcmaHandleScope handleScope(thread); 451 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 452 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 453 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 454 double value = numberValue.GetNumber(); 455 double result = base::NAN_VALUE; 456 // If value is NaN , -NaN , or < -1,result is NaN 457 if (!std::isnan(std::abs(value)) && value >= -1) { 458 result = std::log1p(value); 459 } 460 return GetTaggedDouble(result); 461} 462 463// 20.2.2.22 464JSTaggedValue BuiltinsMath::Log10(EcmaRuntimeCallInfo *argv) 465{ 466 ASSERT(argv); 467 BUILTINS_API_TRACE(argv->GetThread(), Math, Log10); 468 JSThread *thread = argv->GetThread(); 469 [[maybe_unused]] EcmaHandleScope handleScope(thread); 470 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 471 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 472 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 473 double value = numberValue.GetNumber(); 474 double result = base::NAN_VALUE; 475 // If value is NaN , -NaN , or < 0,result is NaN 476 if (!std::isnan(std::abs(value)) && value >= 0) { 477 result = std::log10(value); 478 } 479 return GetTaggedDouble(result); 480} 481 482// 20.2.2.23 483JSTaggedValue BuiltinsMath::Log2(EcmaRuntimeCallInfo *argv) 484{ 485 ASSERT(argv); 486 BUILTINS_API_TRACE(argv->GetThread(), Math, Log2); 487 JSThread *thread = argv->GetThread(); 488 [[maybe_unused]] EcmaHandleScope handleScope(thread); 489 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 490 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 491 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 492 double value = numberValue.GetNumber(); 493 double result = base::NAN_VALUE; 494 // If value is NaN , -NaN , or < 0,result is NaN 495 if (!std::isnan(std::abs(value)) && value >= 0) { 496 result = std::log2(value); 497 } 498 return GetTaggedDouble(result); 499} 500 501inline bool IsNegZero(double value) 502{ 503 return (value == 0.0 && (base::bit_cast<uint64_t>(value) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK); 504} 505 506// 20.2.2.24 507JSTaggedValue BuiltinsMath::Max(EcmaRuntimeCallInfo *argv) 508{ 509 ASSERT(argv); 510 BUILTINS_API_TRACE(argv->GetThread(), Math, Max); 511 JSThread *thread = argv->GetThread(); 512 [[maybe_unused]] EcmaHandleScope handleScope(thread); 513 uint32_t argLen = argv->GetArgsNumber(); 514 auto numberValue = JSTaggedNumber(-base::POSITIVE_INFINITY); 515 // If no arguments are given, the result is -inf 516 auto result = JSTaggedNumber(-base::POSITIVE_INFINITY); 517 auto tmpMax = -base::POSITIVE_INFINITY; 518 auto value = -base::POSITIVE_INFINITY; 519 bool flag = false; 520 uint32_t i = 0; 521 for (; i < argLen; i++) { 522 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i); 523 numberValue = JSTaggedValue::ToNumber(thread, msg); 524 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 525 value = numberValue.GetNumber(); 526 if (std::isnan(std::abs(value))) { 527 // If any value is NaN, or -NaN, the max result is NaN 528 result = numberValue; 529 flag = true; 530 i++; 531 break; 532 } 533 if (value > tmpMax) { 534 result = numberValue; 535 tmpMax = value; 536 } else if (value == 0 && tmpMax == 0 && IsNegZero(tmpMax) && !IsNegZero(value)) { 537 // if tmp_max is -0, value is 0, max is 0 538 result = numberValue; 539 tmpMax = value; 540 } 541 } 542 if (flag) { 543 for (; i < argLen; i++) { 544 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i); 545 numberValue = JSTaggedValue::ToNumber(thread, msg); 546 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 547 } 548 } 549 return result; 550} 551 552// 20.2.2.25 553JSTaggedValue BuiltinsMath::Min(EcmaRuntimeCallInfo *argv) 554{ 555 ASSERT(argv); 556 BUILTINS_API_TRACE(argv->GetThread(), Math, Min); 557 JSThread *thread = argv->GetThread(); 558 [[maybe_unused]] EcmaHandleScope handleScope(thread); 559 uint32_t argLen = argv->GetArgsNumber(); 560 auto numberValue = JSTaggedNumber(base::POSITIVE_INFINITY); 561 // If no arguments are given, the result is inf 562 auto result = JSTaggedNumber(base::POSITIVE_INFINITY); 563 auto tmpMin = base::POSITIVE_INFINITY; 564 auto value = base::POSITIVE_INFINITY; 565 bool flag = false; 566 uint32_t i = 0; 567 for (; i < argLen; i++) { 568 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i); 569 numberValue = JSTaggedValue::ToNumber(thread, msg); 570 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 571 value = numberValue.GetNumber(); 572 if (std::isnan(std::abs(value))) { 573 // If any value is NaN or -NaN, the min result is NaN 574 result = numberValue; 575 flag = true; 576 i++; 577 break; 578 } 579 if (value < tmpMin) { 580 result = numberValue; 581 tmpMin = value; 582 } else if (value == 0 && tmpMin == 0 && !IsNegZero(tmpMin) && IsNegZero(value)) { 583 // if tmp_min is 0, value is -0, min is -0 584 result = numberValue; 585 tmpMin = value; 586 } 587 } 588 if (flag) { 589 for (; i < argLen; i++) { 590 JSHandle<JSTaggedValue> msg = GetCallArg(argv, i); 591 numberValue = JSTaggedValue::ToNumber(thread, msg); 592 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 593 } 594 } 595 return result; 596} 597 598// 20.2.2.26 599JSTaggedValue BuiltinsMath::Pow(EcmaRuntimeCallInfo *argv) 600{ 601 ASSERT(argv); 602 BUILTINS_API_TRACE(argv->GetThread(), Math, Pow); 603 JSThread *thread = argv->GetThread(); 604 [[maybe_unused]] EcmaHandleScope handleScope(thread); 605 JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 0); 606 JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 1); 607 JSHandle<JSTaggedValue> baseVale = JSTaggedValue::ToNumeric(thread, msgX); 608 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 609 JSHandle<JSTaggedValue> exponentValue = JSTaggedValue::ToNumeric(thread, msgY); 610 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 611 if (baseVale->IsBigInt() || exponentValue->IsBigInt()) { 612 if (baseVale->IsBigInt() && exponentValue->IsBigInt()) { 613 JSHandle<BigInt> bigBaseVale(baseVale); 614 JSHandle<BigInt> bigExponentValue(exponentValue); 615 return BigInt::Exponentiate(thread, bigBaseVale, bigExponentValue).GetTaggedValue(); 616 } 617 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot mix BigInt and other types, use explicit conversions", 618 JSTaggedValue::Exception()); 619 } 620 double valueX = baseVale->GetNumber(); 621 double valueY = exponentValue->GetNumber(); 622 // If abs(x) is 1 and y is inf or -inf, the result is NaN 623 if (std::abs(valueX) == 1 && !std::isfinite(valueY)) { 624 return GetTaggedDouble(base::NAN_VALUE); 625 } 626 double result = std::pow(valueX, valueY); 627 if (std::isnan(std::abs(result))) { 628 // If result is NaN or -NaN, the result is NaN 629 result = base::NAN_VALUE; 630 } 631 return GetTaggedDouble(result); 632} 633 634// 20.2.2.27 635JSTaggedValue BuiltinsMath::Random(EcmaRuntimeCallInfo *argv) 636{ 637 ASSERT(argv); 638 JSThread *thread = argv->GetThread(); 639 BUILTINS_API_TRACE(thread, Math, Random); 640 [[maybe_unused]] EcmaHandleScope handleScope(thread); 641 return GetTaggedDouble(RandomGenerator::NextDouble()); 642} 643 644// 20.2.2.28 645JSTaggedValue BuiltinsMath::Round(EcmaRuntimeCallInfo *argv) 646{ 647 ASSERT(argv); 648 BUILTINS_API_TRACE(argv->GetThread(), Math, Round); 649 JSThread *thread = argv->GetThread(); 650 [[maybe_unused]] EcmaHandleScope handleScope(thread); 651 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 652 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 653 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 654 double value = numberValue.GetNumber(); 655 auto result = base::NAN_VALUE; 656 const double diff = 0.5; 657 double absValue = std::abs(value); 658 if (!std::isfinite(absValue) || absValue == 0) { 659 // If value is NaN, +infinite, or -infinite, VRegisterTag is DOUBLE 660 if (!std::isnan(absValue)) { 661 // If value is NaN or -NaN, the result is default NaN, else is value 662 result = value; 663 } 664 return GetTaggedDouble(result); 665 } 666 // If x is less than 0 but greater than or equal to -0.5, the result is -0 667 if (value < 0 && value >= -diff) { 668 return GetTaggedDouble(-0.0); 669 } 670 // If x is greater than 0 but less than 0.5, the result is +0 671 if (value > 0 && value < diff) { 672 return GetTaggedInt(0); 673 } 674 // For huge integers 675 result = std::ceil(value); 676 if (result - value > diff) { 677 result -= 1; 678 } 679 return GetTaggedDouble(result); 680} 681 682// 20.2.2.29 683JSTaggedValue BuiltinsMath::Sign(EcmaRuntimeCallInfo *argv) 684{ 685 ASSERT(argv); 686 BUILTINS_API_TRACE(argv->GetThread(), Math, Sign); 687 JSThread *thread = argv->GetThread(); 688 [[maybe_unused]] EcmaHandleScope handleScope(thread); 689 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 690 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 691 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 692 double value = numberValue.GetNumber(); 693 if (std::isnan(std::abs(value))) { 694 return GetTaggedDouble(std::abs(value)); 695 } 696 if (value == 0.0) { 697 return GetTaggedDouble(value); 698 } 699 if (value < 0) { 700 return GetTaggedInt(-1); 701 } 702 return GetTaggedInt(1); 703} 704 705// 20.2.2.30 706JSTaggedValue BuiltinsMath::Sin(EcmaRuntimeCallInfo *argv) 707{ 708 ASSERT(argv); 709 BUILTINS_API_TRACE(argv->GetThread(), Math, Sin); 710 JSThread *thread = argv->GetThread(); 711 [[maybe_unused]] EcmaHandleScope handleScope(thread); 712 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 713 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 714 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 715 double value = numberValue.GetNumber(); 716 double result = base::NAN_VALUE; 717 // If value is NaN or -NaN, the result is NaN 718 if (std::isfinite(std::abs(value))) { 719 result = std::sin(value); 720 } 721 return GetTaggedDouble(result); 722} 723 724// 20.2.2.31 725JSTaggedValue BuiltinsMath::Sinh(EcmaRuntimeCallInfo *argv) 726{ 727 ASSERT(argv); 728 BUILTINS_API_TRACE(argv->GetThread(), Math, Sinh); 729 JSThread *thread = argv->GetThread(); 730 [[maybe_unused]] EcmaHandleScope handleScope(thread); 731 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 732 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 733 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 734 double value = numberValue.GetNumber(); 735 double result = base::NAN_VALUE; 736 // If value is NaN or -NaN, the result is NaN 737 if (!std::isnan(std::abs(value))) { 738 result = std::sinh(value); 739 } 740 return GetTaggedDouble(result); 741} 742 743// 20.2.2.32 744JSTaggedValue BuiltinsMath::Sqrt(EcmaRuntimeCallInfo *argv) 745{ 746 ASSERT(argv); 747 BUILTINS_API_TRACE(argv->GetThread(), Math, Sqrt); 748 JSThread *thread = argv->GetThread(); 749 [[maybe_unused]] EcmaHandleScope handleScope(thread); 750 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 751 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 752 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 753 double value = numberValue.GetNumber(); 754 double result = base::NAN_VALUE; 755 // If value is negative, include -NaN and -Infinity but not -0.0, the result is NaN 756 if (std::signbit(value) && value != 0) { 757 return GetTaggedDouble(result); 758 } 759 // If value is NaN, the result is NaN 760 if (!std::isnan(value)) { 761 result = std::sqrt(value); 762 } 763 return GetTaggedDouble(result); 764} 765 766// 20.2.2.33 767JSTaggedValue BuiltinsMath::Tan(EcmaRuntimeCallInfo *argv) 768{ 769 ASSERT(argv); 770 BUILTINS_API_TRACE(argv->GetThread(), Math, Tan); 771 JSThread *thread = argv->GetThread(); 772 [[maybe_unused]] EcmaHandleScope handleScope(thread); 773 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 774 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 775 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 776 double value = numberValue.GetNumber(); 777 double result = base::NAN_VALUE; 778 // If value is NaN or -NaN, +infinite, -infinite, result is NaN 779 if (std::isfinite(value)) { 780 result = std::tan(value); 781 } 782 return GetTaggedDouble(result); 783} 784 785// 20.2.2.34 786JSTaggedValue BuiltinsMath::Tanh(EcmaRuntimeCallInfo *argv) 787{ 788 ASSERT(argv); 789 BUILTINS_API_TRACE(argv->GetThread(), Math, Tanh); 790 JSThread *thread = argv->GetThread(); 791 [[maybe_unused]] EcmaHandleScope handleScope(thread); 792 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 793 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 794 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 795 double value = numberValue.GetNumber(); 796 double result = base::NAN_VALUE; 797 if (!std::isnan(std::abs(value))) { 798 result = std::tanh(value); 799 } 800 return GetTaggedDouble(result); 801} 802 803// 20.2.2.35 804JSTaggedValue BuiltinsMath::Trunc(EcmaRuntimeCallInfo *argv) 805{ 806 ASSERT(argv); 807 BUILTINS_API_TRACE(argv->GetThread(), Math, Trunc); 808 JSThread *thread = argv->GetThread(); 809 [[maybe_unused]] EcmaHandleScope handleScope(thread); 810 JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0); 811 JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg); 812 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 813 double value = numberValue.GetNumber(); 814 double result = base::NAN_VALUE; 815 if (!std::isfinite(value)) { 816 // if value is +infinite, -infinite, NaN, -NaN, VRegisterTag is double 817 if (!std::isnan(std::abs(value))) { 818 // if value is +infinite, -infinite, result is value 819 result = value; 820 } 821 } else { 822 result = std::trunc(value); 823 } 824 return GetTaggedDouble(result); 825} 826} // namespace panda::ecmascript::builtins 827