1 /** 2 * Copyright (c) 2021-2022 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 BYTECODE_OPTIMIZER_TAGGED_VALUE_H 17 #define BYTECODE_OPTIMIZER_TAGGED_VALUE_H 18 19 #include <climits> 20 #include <cstddef> 21 #include "macros.h" 22 #include "libpandabase/mem/mem.h" 23 #include "utils/bit_utils.h" 24 25 namespace panda::coretypes { 26 27 // Every double with all of its exponent bits set and its highest mantissa bit set is a quiet NaN. 28 // That leaves 51 bits unaccounted for. We’ll avoid one of those so that we don’t step on Intel’s 29 // “QNaN Floating-Point Indefinite” value, leaving us 50 bits. Those remaining bits can be anything. 30 // so we use a special quietNaN as TaggedInt tag(highest 16bits as 0xFFFF), and need to encode double 31 // to the value will begin with a 16-bit pattern within the range 0x0001..0xFFFE. 32 33 // Nan-boxing pointer is used and the first four bytes are used as tag: 34 // Object: [0x0000] [48 bit direct pointer] 35 // WeakRef: [0x0000] [47 bits direct pointer] | 1 bit 1 36 // / [0x0001] [48 bit any value] 37 // TaggedDouble: ...... 38 // \ [0xFFFE] [48 bit any value] 39 // TaggedInt: [0xFFFF] [0x0000] [32 bit signed integer] 40 // 41 // There are some special markers of Object: 42 // False: [56 bits 0] | 0x06 // 0110 43 // True: [56 bits 0] | 0x07 // 0111 44 // Undefined: [56 bits 0] | 0x0a // 1010 45 // Null: [56 bits 0] | 0x02 // 0010 46 // Hole: [56 bits 0] | 0x00 // 0000 47 48 using TaggedType = uint64_t; 49 ReinterpretDoubleToTaggedType(double value)50inline TaggedType ReinterpretDoubleToTaggedType(double value) 51 { 52 return bit_cast<TaggedType>(value); 53 } ReinterpretTaggedTypeToDouble(TaggedType value)54inline double ReinterpretTaggedTypeToDouble(TaggedType value) 55 { 56 return bit_cast<double>(value); 57 } 58 59 class TaggedValue { 60 public: 61 static constexpr size_t TAG_BITS_SIZE = 16; 62 static constexpr size_t TAG_BITS_SHIFT = BitNumbers<TaggedType>() - TAG_BITS_SIZE; 63 static_assert((TAG_BITS_SHIFT + TAG_BITS_SIZE) == sizeof(TaggedType) * CHAR_BIT, "Insufficient bits!"); 64 static constexpr TaggedType TAG_MASK = ((1ULL << TAG_BITS_SIZE) - 1ULL) << TAG_BITS_SHIFT; 65 static constexpr TaggedType TAG_INT = TAG_MASK; 66 static constexpr TaggedType TAG_OBJECT = 0x0000ULL << TAG_BITS_SHIFT; 67 static constexpr TaggedType OBJECT_MASK = ~TAG_INT; 68 69 static constexpr TaggedType TAG_SPECIAL_MASK = 0xFFULL; 70 static constexpr TaggedType TAG_SPECIAL_VALUE = 0x02ULL; 71 static constexpr TaggedType TAG_BOOLEAN = 0x04ULL; 72 static constexpr TaggedType TAG_UNDEFINED = 0x08ULL; 73 static constexpr TaggedType TAG_EXCEPTION = 0x10ULL; 74 static constexpr TaggedType TAG_WEAK_FILTER = 0x03ULL; 75 static constexpr TaggedType VALUE_HOLE = TAG_OBJECT | 0x00ULL; 76 static constexpr TaggedType TAG_WEAK_MASK = TAG_OBJECT | 0x01ULL; 77 static constexpr TaggedType VALUE_NULL = TAG_OBJECT | TAG_SPECIAL_VALUE; 78 static constexpr TaggedType VALUE_FALSE = 79 TAG_OBJECT | TAG_BOOLEAN | TAG_SPECIAL_VALUE | static_cast<TaggedType>(false); 80 static constexpr TaggedType VALUE_TRUE = 81 TAG_OBJECT | TAG_BOOLEAN | TAG_SPECIAL_VALUE | static_cast<TaggedType>(true); 82 static constexpr TaggedType VALUE_ZERO = TAG_INT | 0x00ULL; 83 static constexpr TaggedType VALUE_UNDEFINED = TAG_OBJECT | TAG_SPECIAL_VALUE | TAG_UNDEFINED; 84 static constexpr TaggedType VALUE_EXCEPTION = TAG_OBJECT | TAG_SPECIAL_VALUE | TAG_EXCEPTION; 85 86 static constexpr size_t DOUBLE_ENCODE_OFFSET_BIT = 48; 87 static constexpr TaggedType DOUBLE_ENCODE_OFFSET = 1ULL << DOUBLE_ENCODE_OFFSET_BIT; 88 89 TaggedValue(void *) = delete; 90 91 static const TaggedType NULL_POINTER = 0; TaggedValue()92 constexpr TaggedValue() : value_(NULL_POINTER) {} 93 TaggedValue(TaggedType v)94 constexpr explicit TaggedValue(TaggedType v) : value_(v) {} 95 TaggedValue(int v)96 constexpr explicit TaggedValue(int v) : value_(static_cast<TaggedType>(v) | TAG_INT) {} 97 TaggedValue(unsigned int v)98 explicit TaggedValue(unsigned int v) 99 { 100 if (static_cast<int32_t>(v) < 0) { 101 value_ = TaggedValue(static_cast<double>(v)).GetRawData(); 102 return; 103 } 104 value_ = TaggedValue(static_cast<int32_t>(v)).GetRawData(); 105 } 106 TaggedValue(int64_t v)107 explicit TaggedValue(int64_t v) 108 { 109 if (UNLIKELY(static_cast<int32_t>(v) != v)) { 110 value_ = TaggedValue(static_cast<double>(v)).GetRawData(); 111 return; 112 } 113 value_ = TaggedValue(static_cast<int32_t>(v)).GetRawData(); 114 } 115 TaggedValue(bool v)116 constexpr explicit TaggedValue(bool v) 117 : value_(static_cast<TaggedType>(v) | TAG_OBJECT | TAG_BOOLEAN | TAG_SPECIAL_VALUE) 118 { 119 } 120 TaggedValue(double v)121 explicit TaggedValue(double v) 122 { 123 ASSERT_PRINT(!IsImpureNaN(v), "pureNaN will break the encoding of tagged double: " 124 << std::hex << ReinterpretDoubleToTaggedType(v)); 125 value_ = ReinterpretDoubleToTaggedType(v) + DOUBLE_ENCODE_OFFSET; 126 } 127 TaggedValue(ObjectHeader * v)128 explicit TaggedValue(ObjectHeader *v) : value_(static_cast<TaggedType>(ToUintPtr(v))) {} 129 TaggedValue(const ObjectHeader * v)130 explicit TaggedValue(const ObjectHeader *v) : value_(static_cast<TaggedType>(ToUintPtr(v))) {} 131 IsBoolean()132 inline bool IsBoolean() const 133 { 134 return value_ == VALUE_FALSE || value_ == VALUE_TRUE; 135 } 136 GetRawData()137 inline constexpr TaggedType GetRawData() const 138 { 139 return value_; 140 } 141 IsUndefined()142 inline bool IsUndefined() const 143 { 144 return value_ == VALUE_UNDEFINED; 145 } 146 IsImpureNaN(double value)147 static inline bool IsImpureNaN(double value) 148 { 149 // Tests if the double value would break tagged double encoding. 150 return bit_cast<TaggedType>(value) >= (TAG_INT - DOUBLE_ENCODE_OFFSET); 151 } 152 153 inline bool operator==(const TaggedValue &other) const 154 { 155 return value_ == other.value_; 156 } 157 158 inline bool operator!=(const TaggedValue &other) const 159 { 160 return value_ != other.value_; 161 } 162 163 ~TaggedValue() = default; 164 165 DEFAULT_COPY_SEMANTIC(TaggedValue); 166 DEFAULT_MOVE_SEMANTIC(TaggedValue); 167 168 private: 169 TaggedType value_; 170 }; 171 } // namespace panda::coretypes 172 173 #endif // BYTECODE_OPTIMIZER_TAGGED_VALUE_H 174