• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ECMASCRIPT_JS_NUMBER_H
17 #define ECMASCRIPT_JS_NUMBER_H
18 
19 #include "ecmascript/base/number_helper.h"
20 
21 #include "ecmascript/ecma_macros.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/js_hclass.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/js_thread.h"
26 #include "ecmascript/object_factory.h"
27 
28 namespace panda {
29 namespace ecmascript {
30 class JSTaggedNumber final : public JSTaggedValue {
31 public:
32     constexpr JSTaggedNumber() = default;
JSTaggedNumber(double v)33     explicit JSTaggedNumber(double v) : JSTaggedValue(v) {}
JSTaggedNumber(int v)34     constexpr explicit JSTaggedNumber(int v) : JSTaggedValue(v) {}
JSTaggedNumber(unsigned int v)35     explicit JSTaggedNumber(unsigned int v) : JSTaggedValue(v) {}
JSTaggedNumber(JSTaggedValue v)36     explicit JSTaggedNumber(JSTaggedValue v) : JSTaggedValue(v.GetRawData())
37     {
38         ASSERT_PRINT(v.IsNumber(), "can not convert non Number JSTaggedValue to JSTaggedNumber");
39     }
40 
41     ~JSTaggedNumber() = default;
42     DEFAULT_COPY_SEMANTIC(JSTaggedNumber);
43     DEFAULT_MOVE_SEMANTIC(JSTaggedNumber);
44 
Exception()45     static inline constexpr JSTaggedNumber Exception()
46     {
47         return JSTaggedNumber(VALUE_EXCEPTION);
48     }
49 
IsException()50     inline bool IsException() const
51     {
52         return JSTaggedValue::IsException();
53     }
54 
ToInt32()55     inline int32_t ToInt32() const
56     {
57         if (IsInt()) {
58             return GetInt();
59         }
60         return base::NumberHelper::DoubleToInt(GetDouble(), base::INT32_BITS);
61     }
62 
ToUint32()63     inline uint32_t ToUint32() const
64     {
65         return ToInt32();
66     }
67 
ToInt16()68     inline int16_t ToInt16() const
69     {
70         return base::NumberHelper::DoubleToInt(GetNumber(), base::INT16_BITS);
71     }
72 
ToUint16()73     inline uint16_t ToUint16() const
74     {
75         return ToInt16();
76     }
77 
ToInt8()78     inline int8_t ToInt8() const
79     {
80         return base::NumberHelper::DoubleToInt(GetNumber(), base::INT8_BITS);
81     }
82 
ToUint8()83     inline uint8_t ToUint8() const
84     {
85         return ToInt8();
86     }
87 
ToString(const JSThread * thread)88     inline JSHandle<EcmaString> ToString(const JSThread *thread) const
89     {
90         return base::NumberHelper::NumberToString(thread, *this);
91     }
92 
93     JSTaggedNumber operator-(JSTaggedNumber number) const
94     {
95         if (IsInt() && number.IsInt()) {
96             int64_t a0 = GetInt();
97             int64_t a1 = number.GetInt();
98             int64_t res = a0 - a1;
99             if (res > INT32_MAX || res < INT32_MIN) {
100                 return JSTaggedNumber(static_cast<double>(res));
101             }
102             return JSTaggedNumber(static_cast<int>(res));
103         }
104         return JSTaggedNumber(GetNumber() - number.GetNumber());
105     }
106 
107     JSTaggedNumber operator*(JSTaggedNumber number) const
108     {
109         if (IsInt() && number.IsInt()) {
110             int64_t intA = GetInt();
111             int64_t intB = number.GetInt();
112             int64_t res = intA * intB;
113             if (res > INT32_MAX || res < INT32_MIN) {
114                 return JSTaggedNumber(static_cast<double>(res));
115             }
116             if (res == 0 && (intA < 0 || intB < 0)) {
117                 return JSTaggedNumber(-0.0);
118             }
119             return JSTaggedNumber(static_cast<int>(res));
120         }
121         return JSTaggedNumber(GetNumber() * number.GetNumber());
122     }
123 
124     JSTaggedNumber operator++() const
125     {
126         if (IsInt()) {
127             int32_t value = GetInt();
128             if (value == INT32_MAX) {
129                 return JSTaggedNumber(static_cast<double>(value) + 1.0);
130             }
131             return JSTaggedNumber(value + 1);
132         }
133         ASSERT(IsDouble());
134         double doubleVal = GetDouble();
135         if (UNLIKELY(std::isnan(doubleVal) || !std::isfinite(doubleVal))) {
136             return JSTaggedNumber(doubleVal);
137         }
138         return JSTaggedNumber(doubleVal + 1.0);
139     }
140 
141     JSTaggedNumber operator--() const
142     {
143         if (IsInt()) {
144             int32_t value = GetInt();
145             if (value == INT32_MIN) {
146                 return JSTaggedNumber(static_cast<double>(value) - 1.0);
147             }
148             return JSTaggedNumber(value - 1);
149         }
150         ASSERT(IsDouble());
151         double doubleVal = GetDouble();
152         if (UNLIKELY(std::isnan(doubleVal) || !std::isfinite(doubleVal))) {
153             return JSTaggedNumber(doubleVal);
154         }
155         return JSTaggedNumber(doubleVal - 1.0);
156     }
157 
158     inline bool operator!=(const JSTaggedNumber &number) const
159     {
160         return GetNumber() != number.GetNumber();
161     }
162 
163     /* static */
SameValue(JSTaggedNumber x,JSTaggedNumber y)164     inline static bool SameValue(JSTaggedNumber x, JSTaggedNumber y)
165     {
166         double xValue = x.GetNumber();
167         double yValue = y.GetNumber();
168         // SameNumberValue(NaN, NaN) is true.
169         if (xValue != yValue) {
170             return std::isnan(xValue) && std::isnan(yValue);
171         }
172         // SameNumberValue(0.0, -0.0) is false.
173         return (std::signbit(xValue) == std::signbit(yValue));
174     }
175 
FromIntOrDouble(JSThread * thread,JSTaggedValue tagged)176     inline static JSTaggedNumber FromIntOrDouble(JSThread *thread, JSTaggedValue tagged)
177     {
178         if (tagged.IsInt() || tagged.IsDouble()) {
179             return JSTaggedNumber(tagged);
180         }
181         THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert value to a number", JSTaggedNumber::Exception());
182     }
183 
184 private:
JSTaggedNumber(JSTaggedType v)185     constexpr explicit JSTaggedNumber(JSTaggedType v) : JSTaggedValue(v) {}
186 };
187 }  // namespace ecmascript
188 }  // namespace panda
189 #endif  // ECMASCRIPT_JS_NUMBER_H
190