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