• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BUILTINS_BUILTINS_NUMBER_H
17 #define ECMASCRIPT_BUILTINS_BUILTINS_NUMBER_H
18 
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/js_tagged_value.h"
21 
22 // List of constants in Number, excluding '@@' internal properties.
23 #define BUILTIN_NUMBER_CONSTANTS(V)                             \
24     V(EPSILON)           /* Number.EPSILON */                   \
25     V(MAX_SAFE_INTEGER)  /* Number.MAX_SAFE_INTEGER */          \
26     V(MAX_VALUE)         /* Number.MAX_VALUE */                 \
27     V(MIN_SAFE_INTEGER)  /* Number.MIN_SAFE_INTEGER */          \
28     V(MIN_VALUE)         /* Number.MIN_VALUE */                 \
29     V(NEGATIVE_INFINITY) /* Number.NEGATIVE_INFINITY */         \
30     V(NaN)               /* Number.NaN */                       \
31     V(POSITIVE_INFINITY) /* Number.POSITIVE_INFINITY */
32 
33 // List of functions in Number.
34 // V(name, func, length, stubIndex)
35 // where BuiltinsNumber::func refers to the native implementation of Number[name].
36 //       kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
37 #define BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V)                                          \
38     V("isFinite",      IsFinite,      1, INVALID) /* Number.isFinite ( number ) */      \
39     V("isInteger",     IsInteger,     1, INVALID) /* Number.isInteger ( number ) */     \
40     V("isNaN",         IsNaN,         1, INVALID) /* Number.isNaN ( number ) */         \
41     V("isSafeInteger", IsSafeInteger, 1, INVALID) /* Number.isSafeInteger ( number ) */
42 
43 // List of functions in Number that can be accessed via globalThis.
44 // V(name, func, length, stubIndex)
45 // where BuiltinsNumber::func refers to the native implementation of Number[name].
46 #define BUILTIN_NUMBER_GLOBAL_FUNCTIONS(V)                                              \
47     V("parseFloat", ParseFloat, 1, NumberParseFloat) /* Number.parseFloat ( string ) */ \
48     V("parseInt",   ParseInt,   2, INVALID) /* Number.parseInt ( string, radix ) */
49 
50 #define BUILTIN_NUMBER_FUNCTIONS(V)         \
51     BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V)  \
52     BUILTIN_NUMBER_GLOBAL_FUNCTIONS(V)
53 
54 // List of functions in Number.prototype, excluding the constructor and '@@' properties.
55 // V(name, func, length, stubIndex)
56 // where BuiltinsNumber::func refers to the native implementation of Number.prototype[name].
57 #define BUILTIN_NUMBER_PROTOTYPE_FUNCTIONS(V)                               \
58     /* Number.prototype.toExponential ( fractionDigits ) */                 \
59     V("toExponential",  ToExponential,  1, INVALID)                         \
60     /* Number.prototype.toFixed ( fractionDigits ) */                       \
61     V("toFixed",        ToFixed,        1, INVALID)                         \
62     /* Number.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) */ \
63     V("toLocaleString", ToLocaleString, 0, INVALID)                         \
64     /* Number.prototype.toPrecision ( precision ) */                        \
65     V("toPrecision",    ToPrecision,    1, INVALID)                         \
66     /* Number.prototype.toString ( [ radix ] ) */                           \
67     V("toString",       ToString,       1, INVALID)                         \
68     /* Number.prototype.valueOf ( ) */                                      \
69     V("valueOf",        ValueOf,        0, INVALID)
70 
71 namespace panda::ecmascript::builtins {
72 class BuiltinsNumber : public base::BuiltinsBase {
73 public:
74     // 21.1.2.1 Number.EPSILON
75     static constexpr double EPSILON = std::numeric_limits<double>::epsilon();
76     // 21.1.2.6 Number.MAX_SAFE_INTEGER (which is 2**53 - 1 = 9007199254740991)
77     static constexpr int64_t MAX_SAFE_INTEGER = (1LL << 53) - 1;
78     // 21.1.2.8 Number.MIN_SAFE_INTEGER (which is -(2**53 - 1) = -9007199254740991)
79     static constexpr int64_t MIN_SAFE_INTEGER = -((1LL << 53) - 1);
80     // 21.1.2.7 Number.MAX_VALUE
81     static constexpr double MAX_VALUE = std::numeric_limits<double>::max();
82     // 21.1.2.9 Number.MIN_VALUE
83     static constexpr double MIN_VALUE = std::numeric_limits<double>::denorm_min();
84     // 21.1.2.14 Number.POSITIVE_INFINITY
85     static constexpr double POSITIVE_INFINITY = std::numeric_limits<double>::infinity();
86     // 21.1.2.11 Number.NEGATIVE_INFINITY
87     static constexpr double NEGATIVE_INFINITY = -POSITIVE_INFINITY;
88     // 21.1.2.10 Number.NaN
89     static constexpr double NaN = NAN;
90 
91     // 20.1.1.1
92     static JSTaggedValue NumberConstructor(EcmaRuntimeCallInfo *argv);
93 
94     // 20.1.2.2
95     static JSTaggedValue IsFinite(EcmaRuntimeCallInfo *argv);
96     // 20.1.2.3
97     static JSTaggedValue IsInteger(EcmaRuntimeCallInfo *argv);
98     // 20.1.2.4
99     static JSTaggedValue IsNaN(EcmaRuntimeCallInfo *argv);
100     // 20.1.2.5
101     static JSTaggedValue IsSafeInteger(EcmaRuntimeCallInfo *argv);
102     // 20.1.2.12
103     static JSTaggedValue ParseFloat(EcmaRuntimeCallInfo *argv);
104     // 20.1.2.13
105     static JSTaggedValue ParseInt(EcmaRuntimeCallInfo *argv);
106 
107     // prototype
108     // 20.1.3.2
109     static JSTaggedValue ToExponential(EcmaRuntimeCallInfo *argv);
110     // 20.1.3.3
111     static JSTaggedValue ToFixed(EcmaRuntimeCallInfo *argv);
112     // 20.1.3.4
113     static JSTaggedValue ToLocaleString(EcmaRuntimeCallInfo *argv);
114     // 20.1.3.5
115     static JSTaggedValue ToPrecision(EcmaRuntimeCallInfo *argv);
116     // 20.1.3.6
117     static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv);
118     // 20.1.3.7
119     static JSTaggedValue ValueOf(EcmaRuntimeCallInfo *argv);
120 
121     // Excluding the '@@' internal properties.
GetNumberConstants()122     static Span<const base::BuiltinConstantEntry> GetNumberConstants()
123     {
124         return Span<const base::BuiltinConstantEntry>(NUMBER_CONSTANTS);
125     }
126 
127     // Excluding the '@@' internal properties.
GetNumberNonGlobalFunctions()128     static Span<const base::BuiltinFunctionEntry> GetNumberNonGlobalFunctions()
129     {
130         return Span<const base::BuiltinFunctionEntry>(NUMBER_NON_GLOBAL_FUNCTIONS);
131     }
132 
133     // Excluding the '@@' internal properties.
GetNumberGlobalFunctions()134     static Span<const base::BuiltinFunctionEntry> GetNumberGlobalFunctions()
135     {
136         return Span<const base::BuiltinFunctionEntry>(NUMBER_GLOBAL_FUNCTIONS);
137     }
138 
139     // Excluding the constructor and '@@' internal properties.
GetNumberPrototypeFunctions()140     static Span<const base::BuiltinFunctionEntry> GetNumberPrototypeFunctions()
141     {
142         return Span<const base::BuiltinFunctionEntry>(NUMBER_PROTOTYPE_FUNCTIONS);
143     }
144 
145 private:
146 #define BUILTIN_NUMBER_CONSTANT_ENTRY(name) \
147     base::BuiltinConstantEntry::Create(#name, JSTaggedValue(BuiltinsNumber::name)),
148 
149     static inline std::array NUMBER_CONSTANTS = {
150         BUILTIN_NUMBER_CONSTANTS(BUILTIN_NUMBER_CONSTANT_ENTRY)
151     };
152 #undef BUILTIN_NUMBER_CONSTANT_ENTRY
153 
154 #define BUILTIN_NUMBER_FUNCTION_ENTRY(name, func, length, id) \
155     base::BuiltinFunctionEntry::Create(name, BuiltinsNumber::func, length, kungfu::BuiltinsStubCSigns::id),
156 
157     static constexpr std::array NUMBER_NON_GLOBAL_FUNCTIONS = {
158         BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
159     };
160     static constexpr std::array NUMBER_GLOBAL_FUNCTIONS = {
161         BUILTIN_NUMBER_GLOBAL_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
162     };
163     static constexpr std::array NUMBER_PROTOTYPE_FUNCTIONS = {
164         BUILTIN_NUMBER_PROTOTYPE_FUNCTIONS(BUILTIN_NUMBER_FUNCTION_ENTRY)
165     };
166 #undef BUILTIN_NUMBER_FUNCTION_ENTRY
167 
168     static JSTaggedNumber ThisNumberValue(JSThread *thread, EcmaRuntimeCallInfo *argv);
169 };
170 
171 class NumberToStringResultCache : public TaggedArray {
172 public:
Cast(TaggedObject * object)173     static NumberToStringResultCache *Cast(TaggedObject *object)
174     {
175         return reinterpret_cast<NumberToStringResultCache*>(object);
176     }
177     static JSTaggedValue CreateCacheTable(const JSThread *thread);
178     JSTaggedValue FindCachedResult(JSTaggedValue &number);
179     void SetCachedResult(const JSThread *thread, JSTaggedValue &number, JSHandle<EcmaString> &result);
GetNumberHash(JSTaggedValue & number)180     int GetNumberHash(JSTaggedValue &number)
181     {
182         int mask = INITIAL_CACHE_NUMBER - 1;
183         int value = 0;
184         if (number.IsInt()) {
185             value = number.GetInt();
186         } else {
187             int64_t bits = base::bit_cast<int64_t>(number.GetDouble());
188             value = static_cast<int>(bits) ^ static_cast<int>(bits >> 32); // 32: hight 32 bit
189         }
190         return value & mask;
191     }
192 
193 private:
194     static constexpr int INITIAL_CACHE_NUMBER = 256;
195     static constexpr int NUMBER_INDEX = 0;
196     static constexpr int RESULT_INDEX = 1;
197     static constexpr int ENTRY_SIZE = 2;
198 };
199 }  // namespace panda::ecmascript::builtins
200 #endif  // ECMASCRIPT_BUILTINS_BUILTINS_NUBMER_H
201