* 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.
*/
#ifndef ECMASCRIPT_BUILTINS_BUILTINS_NUMBER_H
#define ECMASCRIPT_BUILTINS_BUILTINS_NUMBER_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/js_tagged_value.h"
#define BUILTIN_NUMBER_CONSTANTS(V) \
V(EPSILON) \
V(MAX_SAFE_INTEGER) \
V(MAX_VALUE) \
V(MIN_SAFE_INTEGER) \
V(MIN_VALUE) \
V(NEGATIVE_INFINITY) \
V(NaN) \
V(POSITIVE_INFINITY)
#define BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V) \
V("isFinite", IsFinite, 1, NumberIsFinite) \
V("isInteger", IsInteger, 1, NumberIsInteger) \
V("isNaN", IsNaN, 1, NumberIsNaN) \
V("isSafeInteger", IsSafeInteger, 1, NumberIsSafeInteger)
#define BUILTIN_NUMBER_GLOBAL_FUNCTIONS(V) \
V("parseFloat", ParseFloat, 1, NumberParseFloat) \
V("parseInt", ParseInt, 2, NumberParseInt)
#define BUILTIN_NUMBER_FUNCTIONS(V) \
BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V) \
BUILTIN_NUMBER_GLOBAL_FUNCTIONS(V)
#define BUILTIN_NUMBER_PROTOTYPE_FUNCTIONS(V) \
\
V("toExponential", ToExponential, 1, INVALID) \
\
V("toFixed", ToFixed, 1, INVALID) \
\
V("toLocaleString", ToLocaleString, 0, INVALID) \
\
V("toPrecision", ToPrecision, 1, INVALID) \
\
V("toString", ToString, 1, NumberToStringFunc) \
\
V("valueOf", ValueOf, 0, INVALID)
namespace panda::ecmascript::builtins {
class BuiltinsNumber : public base::BuiltinsBase {
public:
static constexpr double EPSILON = std::numeric_limits<double>::epsilon();
static constexpr int64_t MAX_SAFE_INTEGER = (1LL << 53) - 1;
static constexpr int64_t MIN_SAFE_INTEGER = -((1LL << 53) - 1);
static constexpr double MAX_VALUE = std::numeric_limits<double>::max();
static constexpr double MIN_VALUE = std::numeric_limits<double>::denorm_min();
static constexpr double POSITIVE_INFINITY = std::numeric_limits<double>::infinity();
static constexpr double NEGATIVE_INFINITY = -POSITIVE_INFINITY;
static constexpr double NaN = NAN;
static JSTaggedValue NumberConstructor(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsFinite(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsInteger(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsNaN(EcmaRuntimeCallInfo *argv);
static JSTaggedValue IsSafeInteger(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ParseFloat(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ParseInt(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToExponential(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToFixed(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToLocaleString(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToPrecision(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
static JSTaggedValue ValueOf(EcmaRuntimeCallInfo *argv);
static Span<const base::BuiltinConstantEntry> GetNumberConstants()
{
return Span<const base::BuiltinConstantEntry>(NUMBER_CONSTANTS);
}
static Span<const base::BuiltinFunctionEntry> GetNumberNonGlobalFunctions()
{
return Span<const base::BuiltinFunctionEntry>(NUMBER_NON_GLOBAL_FUNCTIONS);
}
static Span<const base::BuiltinFunctionEntry> GetNumberGlobalFunctions()
{
return Span<const base::BuiltinFunctionEntry>(NUMBER_GLOBAL_FUNCTIONS);
}
static Span<const base::BuiltinFunctionEntry> GetNumberPrototypeFunctions()
{
return Span<const base::BuiltinFunctionEntry>(NUMBER_PROTOTYPE_FUNCTIONS);
}
private:
#define BUILTIN_NUMBER_CONSTANT_ENTRY(name) \
base::BuiltinConstantEntry::Create(#name, JSTaggedValue(BuiltinsNumber::name)),
static inline std::array NUMBER_CONSTANTS = {
BUILTIN_NUMBER_CONSTANTS(BUILTIN_NUMBER_CONSTANT_ENTRY)
};
#undef BUILTIN_NUMBER_CONSTANT_ENTRY
#define BUILTIN_NUMBER_FUNCTION_ENTRY(name, func, length, id) \
base::BuiltinFunctionEntry::Create(name, BuiltinsNumber::func, length, BUILTINS_STUB_ID(id)),
static constexpr std::array NUMBER_NON_GLOBAL_FUNCTIONS = {
BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
};
static constexpr std::array NUMBER_GLOBAL_FUNCTIONS = {
BUILTIN_NUMBER_GLOBAL_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
};
static constexpr std::array NUMBER_PROTOTYPE_FUNCTIONS = {
BUILTIN_NUMBER_PROTOTYPE_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
};
#undef BUILTIN_NUMBER_FUNCTION_ENTRY
static JSTaggedNumber ThisNumberValue(JSThread *thread, EcmaRuntimeCallInfo *argv);
};
class NumberToStringResultCache : public TaggedArray {
public:
static NumberToStringResultCache *Cast(TaggedObject *object)
{
return reinterpret_cast<NumberToStringResultCache*>(object);
}
static JSTaggedValue CreateCacheTable(const JSThread *thread);
JSTaggedValue FindCachedResult(const JSThread *thread, int entry, JSTaggedValue &target);
void SetCachedResult(const JSThread *thread, int entry, JSTaggedValue &number, JSHandle<EcmaString> &result);
int GetNumberHash(JSTaggedValue &number)
{
unsigned int mask = INITIAL_CACHE_NUMBER - 1;
unsigned int value = 0;
if (number.IsInt()) {
value = static_cast<unsigned int>(number.GetInt());
} else {
int64_t bits = base::bit_cast<int64_t>(number.GetDouble());
value = static_cast<unsigned int>(bits) ^ static_cast<unsigned int>(bits >> 32);
}
return value & mask;
}
private:
static constexpr int INITIAL_CACHE_NUMBER = 256;
static constexpr int NUMBER_INDEX = 0;
static constexpr int RESULT_INDEX = 1;
static constexpr int ENTRY_SIZE = 2;
};
}
#endif