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