* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_math.h"
#include "ecmascript/js_tagged_value-inl.h"
namespace panda::ecmascript::builtins {
using NumberHelper = base::NumberHelper;
using RandomGenerator = base::RandomGenerator;
JSTaggedValue BuiltinsMath::Abs(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Abs);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (numberValue.IsDouble()) {
return GetTaggedDouble(std::fabs(numberValue.GetDouble()));
}
int value = numberValue.GetInt();
if (value == INT_MIN) {
return GetTaggedDouble(-static_cast<int64_t>(INT_MIN));
}
return GetTaggedInt(std::abs(value));
}
JSTaggedValue BuiltinsMath::Acos(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Acos);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value)) && value <= 1 && value >= -1) {
result = std::acos(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Acosh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Acosh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (value >= 1) {
result = std::acosh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Asin(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Asin);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (value >= -1 && value <= 1) {
result = std::asin(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Asinh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Asinh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = base::MathHelper::Asinh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Atan(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Atan);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::atan(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Atanh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Atanh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (value >= -1 && value <= 1) {
result = base::MathHelper::Atanh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Atan2(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Atan2);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 1);
double result = base::NAN_VALUE;
JSTaggedNumber numberValueY = JSTaggedValue::ToNumber(thread, msgY);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSTaggedNumber numberValueX = JSTaggedValue::ToNumber(thread, msgX);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double valueY = numberValueY.GetNumber();
double valueX = numberValueX.GetNumber();
if (valueY == 0 && valueX > 0) {
result = valueY;
} else if (std::isfinite(valueY) && valueX == std::numeric_limits<double>::infinity()) {
result = valueY >= 0 ? 0 : -0.0;
} else if (!std::isnan(std::abs(valueY)) && !std::isnan(std::abs(valueX))) {
result = std::atan2(valueY, valueX);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Cbrt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Cbrt);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::cbrt(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Ceil(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Ceil);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isfinite(value)) {
if (!std::isnan(std::abs(value))) {
result = value;
}
} else {
result = std::ceil(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Clz32(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Clz32);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
constexpr int defaultValue = 32;
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
auto tmpValue = std::abs(value);
auto result = numberValue.ToUint32();
if (!std::isfinite(tmpValue) || tmpValue == 0 || result == 0) {
return GetTaggedInt(defaultValue);
}
return GetTaggedInt(__builtin_clz(result));
}
JSTaggedValue BuiltinsMath::Cos(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Cos);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (std::isfinite(std::abs(value))) {
result = std::cos(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Cosh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Cosh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::cosh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Exp(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Exp);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::exp(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Expm1(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Expm1);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::expm1(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Floor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Floor);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isfinite(value) || value == 0) {
if (!std::isnan(std::abs(value))) {
result = value;
}
} else if (value > 0 && value < 1) {
result = 0;
} else {
result = std::floor(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Fround(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Fround);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result;
if (std::isnan(std::abs(value))) {
result = base::NAN_VALUE;
} else {
result = static_cast<float>(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Hypot(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Hypot);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
double result = 0;
double value = 0;
uint32_t argLen = argv->GetArgsNumber();
auto numberValue = JSTaggedNumber(0);
for (uint32_t i = 0; i < argLen; i++) {
JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
value = numberValue.GetNumber();
result = std::hypot(result, value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Imul(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Imul);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg1 = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> msg2 = GetCallArg(argv, 1);
JSTaggedNumber numberValue1 = JSTaggedValue::ToNumber(thread, msg1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSTaggedNumber numberValue2 = JSTaggedValue::ToNumber(thread, msg2);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
auto value1 = numberValue1.GetNumber();
auto value2 = numberValue2.GetNumber();
if (!std::isfinite(value1) || !std::isfinite(value2)) {
return GetTaggedInt(0);
}
value1 = numberValue1.ToInt32();
value2 = numberValue2.ToInt32();
auto result = static_cast<int32_t>(static_cast<int64_t>(value1) * static_cast<int64_t>(value2));
return GetTaggedInt(result);
}
JSTaggedValue BuiltinsMath::Log(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Log);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value)) && value >= 0) {
result = std::log(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Log1p(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Log1p);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value)) && value >= -1) {
result = std::log1p(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Log10(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Log10);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value)) && value >= 0) {
result = std::log10(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Log2(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Log2);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value)) && value >= 0) {
result = std::log2(value);
}
return GetTaggedDouble(result);
}
inline bool IsNegZero(double value)
{
return (value == 0.0 && (base::bit_cast<uint64_t>(value) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK);
}
JSTaggedValue BuiltinsMath::Max(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Max);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
uint32_t argLen = argv->GetArgsNumber();
auto numberValue = JSTaggedNumber(-base::POSITIVE_INFINITY);
auto result = JSTaggedNumber(-base::POSITIVE_INFINITY);
auto tmpMax = -base::POSITIVE_INFINITY;
auto value = -base::POSITIVE_INFINITY;
bool flag = false;
uint32_t i = 0;
for (; i < argLen; i++) {
JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
value = numberValue.GetNumber();
if (std::isnan(std::abs(value))) {
result = numberValue;
flag = true;
i++;
break;
}
if (value > tmpMax) {
result = numberValue;
tmpMax = value;
} else if (value == 0 && tmpMax == 0 && IsNegZero(tmpMax) && !IsNegZero(value)) {
result = numberValue;
tmpMax = value;
}
}
if (flag) {
for (; i < argLen; i++) {
JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
return result;
}
JSTaggedValue BuiltinsMath::Min(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Min);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
uint32_t argLen = argv->GetArgsNumber();
auto numberValue = JSTaggedNumber(base::POSITIVE_INFINITY);
auto result = JSTaggedNumber(base::POSITIVE_INFINITY);
auto tmpMin = base::POSITIVE_INFINITY;
auto value = base::POSITIVE_INFINITY;
bool flag = false;
uint32_t i = 0;
for (; i < argLen; i++) {
JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
value = numberValue.GetNumber();
if (std::isnan(std::abs(value))) {
result = numberValue;
flag = true;
i++;
break;
}
if (value < tmpMin) {
result = numberValue;
tmpMin = value;
} else if (value == 0 && tmpMin == 0 && !IsNegZero(tmpMin) && IsNegZero(value)) {
result = numberValue;
tmpMin = value;
}
}
if (flag) {
for (; i < argLen; i++) {
JSHandle<JSTaggedValue> msg = GetCallArg(argv, i);
numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
}
return result;
}
JSTaggedValue BuiltinsMath::Pow(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Pow);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msgX = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> msgY = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> baseVale = JSTaggedValue::ToNumeric(thread, msgX);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> exponentValue = JSTaggedValue::ToNumeric(thread, msgY);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (baseVale->IsBigInt() || exponentValue->IsBigInt()) {
if (baseVale->IsBigInt() && exponentValue->IsBigInt()) {
JSHandle<BigInt> bigBaseVale(baseVale);
JSHandle<BigInt> bigExponentValue(exponentValue);
return BigInt::Exponentiate(thread, bigBaseVale, bigExponentValue).GetTaggedValue();
}
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot mix BigInt and other types, use explicit conversions",
JSTaggedValue::Exception());
}
double valueX = baseVale->GetNumber();
double valueY = exponentValue->GetNumber();
if (std::abs(valueX) == 1 && !std::isfinite(valueY)) {
return GetTaggedDouble(base::NAN_VALUE);
}
double result = std::pow(valueX, valueY);
if (std::isnan(std::abs(result))) {
result = base::NAN_VALUE;
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Random(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Math, Random);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
return GetTaggedDouble(RandomGenerator::NextDouble());
}
JSTaggedValue BuiltinsMath::Round(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Round);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
auto result = base::NAN_VALUE;
const double diff = 0.5;
double absValue = std::abs(value);
if (!std::isfinite(absValue) || absValue == 0) {
if (!std::isnan(absValue)) {
result = value;
}
return GetTaggedDouble(result);
}
if (value < 0 && value >= -diff) {
return GetTaggedDouble(-0.0);
}
if (value > 0 && value < diff) {
return GetTaggedInt(0);
}
result = std::ceil(value);
if (result - value > diff) {
result -= 1;
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Sign(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Sign);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
if (std::isnan(std::abs(value))) {
return GetTaggedDouble(std::abs(value));
}
if (value == 0.0) {
return GetTaggedDouble(value);
}
if (value < 0) {
return GetTaggedInt(-1);
}
return GetTaggedInt(1);
}
JSTaggedValue BuiltinsMath::Sin(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Sin);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (std::isfinite(std::abs(value))) {
result = std::sin(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Sinh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Sinh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::sinh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Sqrt(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Sqrt);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (std::signbit(value) && value != 0) {
return GetTaggedDouble(result);
}
if (!std::isnan(value)) {
result = std::sqrt(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Tan(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Tan);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (std::isfinite(value)) {
result = std::tan(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Tanh(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Tanh);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isnan(std::abs(value))) {
result = std::tanh(value);
}
return GetTaggedDouble(result);
}
JSTaggedValue BuiltinsMath::Trunc(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), Math, Trunc);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, msg);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (!std::isfinite(value)) {
if (!std::isnan(std::abs(value))) {
result = value;
}
} else {
result = std::trunc(value);
}
return GetTaggedDouble(result);
}
}