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