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