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 return JSTaggedNumber(GetDouble() + 1.0); 134 } 135 136 JSTaggedNumber operator--() const 137 { 138 if (IsInt()) { 139 int32_t value = GetInt(); 140 if (value == INT32_MIN) { 141 return JSTaggedNumber(static_cast<double>(value) - 1.0); 142 } 143 return JSTaggedNumber(value - 1); 144 } 145 return JSTaggedNumber(GetDouble() - 1.0); 146 } 147 148 inline bool operator!=(const JSTaggedNumber &number) const 149 { 150 return GetNumber() != number.GetNumber(); 151 } 152 153 /* static */ SameValue(JSTaggedNumber x,JSTaggedNumber y)154 inline static bool SameValue(JSTaggedNumber x, JSTaggedNumber y) 155 { 156 double xValue = x.GetNumber(); 157 double yValue = y.GetNumber(); 158 // SameNumberValue(NaN, NaN) is true. 159 if (xValue != yValue) { 160 return std::isnan(xValue) && std::isnan(yValue); 161 } 162 // SameNumberValue(0.0, -0.0) is false. 163 return (std::signbit(xValue) == std::signbit(yValue)); 164 } 165 FromIntOrDouble(JSThread * thread,JSTaggedValue tagged)166 inline static JSTaggedNumber FromIntOrDouble(JSThread *thread, JSTaggedValue tagged) 167 { 168 if (tagged.IsInt() || tagged.IsDouble()) { 169 return JSTaggedNumber(tagged); 170 } 171 THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot convert value to a number", JSTaggedNumber::Exception()); 172 } 173 174 private: JSTaggedNumber(JSTaggedType v)175 constexpr explicit JSTaggedNumber(JSTaggedType v) : JSTaggedValue(v) {} 176 }; 177 } // namespace ecmascript 178 } // namespace panda 179 #endif // ECMASCRIPT_JS_NUMBER_H 180