| 1 | // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef V8_OBJECTS_NAME_H_ |
| 6 | #define V8_OBJECTS_NAME_H_ |
| 7 | |
| 8 | #include "src/objects.h" |
| 9 | #include "src/objects/heap-object.h" |
| 10 | #include "torque-generated/class-definitions-from-dsl.h" |
| 11 | |
| 12 | // Has to be the last include (doesn't have include guards): |
| 13 | #include "src/objects/object-macros.h" |
| 14 | |
| 15 | namespace v8 { |
| 16 | namespace internal { |
| 17 | |
| 18 | // The Name abstract class captures anything that can be used as a property |
| 19 | // name, i.e., strings and symbols. All names store a hash value. |
| 20 | class Name : public HeapObject { |
| 21 | public: |
| 22 | // Get and set the hash field of the name. |
| 23 | inline uint32_t hash_field(); |
| 24 | inline void set_hash_field(uint32_t value); |
| 25 | |
| 26 | // Tells whether the hash code has been computed. |
| 27 | inline bool HasHashCode(); |
| 28 | |
| 29 | // Returns a hash value used for the property table |
| 30 | inline uint32_t Hash(); |
| 31 | |
| 32 | // Equality operations. |
| 33 | inline bool Equals(Name other); |
| 34 | inline static bool Equals(Isolate* isolate, Handle<Name> one, |
| 35 | Handle<Name> two); |
| 36 | |
| 37 | // Conversion. |
| 38 | inline bool AsArrayIndex(uint32_t* index); |
| 39 | |
| 40 | // An "interesting symbol" is a well-known symbol, like @@toStringTag, |
| 41 | // that's often looked up on random objects but is usually not present. |
| 42 | // We optimize this by setting a flag on the object's map when such |
| 43 | // symbol properties are added, so we can optimize lookups on objects |
| 44 | // that don't have the flag. |
| 45 | inline bool IsInterestingSymbol() const; |
| 46 | |
| 47 | // If the name is private, it can only name own properties. |
| 48 | inline bool IsPrivate(); |
| 49 | |
| 50 | // If the name is a private name, it should behave like a private |
| 51 | // symbol but also throw on property access miss. |
| 52 | inline bool IsPrivateName(); |
| 53 | |
| 54 | inline bool IsUniqueName() const; |
| 55 | |
| 56 | static inline bool ContainsCachedArrayIndex(uint32_t hash); |
| 57 | |
| 58 | // Return a string version of this name that is converted according to the |
| 59 | // rules described in ES6 section 9.2.11. |
| 60 | V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToFunctionName( |
| 61 | Isolate* isolate, Handle<Name> name); |
| 62 | V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToFunctionName( |
| 63 | Isolate* isolate, Handle<Name> name, Handle<String> prefix); |
| 64 | |
| 65 | DECL_CAST(Name) |
| 66 | |
| 67 | DECL_PRINTER(Name) |
| 68 | void NameShortPrint(); |
| 69 | int NameShortPrint(Vector<char> str); |
| 70 | |
| 71 | DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, |
| 72 | TORQUE_GENERATED_NAME_FIELDS) |
| 73 | |
| 74 | static const int = kSize; |
| 75 | |
| 76 | // Mask constant for checking if a name has a computed hash code |
| 77 | // and if it is a string that is an array index. The least significant bit |
| 78 | // indicates whether a hash code has been computed. If the hash code has |
| 79 | // been computed the 2nd bit tells whether the string can be used as an |
| 80 | // array index. |
| 81 | static const int kHashNotComputedMask = 1; |
| 82 | static const int kIsNotArrayIndexMask = 1 << 1; |
| 83 | static const int kNofHashBitFields = 2; |
| 84 | |
| 85 | // Shift constant retrieving hash code from hash field. |
| 86 | static const int kHashShift = kNofHashBitFields; |
| 87 | |
| 88 | // Only these bits are relevant in the hash, since the top two are shifted |
| 89 | // out. |
| 90 | static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift; |
| 91 | |
| 92 | // Array index strings this short can keep their index in the hash field. |
| 93 | static const int kMaxCachedArrayIndexLength = 7; |
| 94 | |
| 95 | // Maximum number of characters to consider when trying to convert a string |
| 96 | // value into an array index. |
| 97 | static const int kMaxArrayIndexSize = 10; |
| 98 | |
| 99 | // For strings which are array indexes the hash value has the string length |
| 100 | // mixed into the hash, mainly to avoid a hash value of zero which would be |
| 101 | // the case for the string '0'. 24 bits are used for the array index value. |
| 102 | static const int kArrayIndexValueBits = 24; |
| 103 | static const int kArrayIndexLengthBits = |
| 104 | kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; |
| 105 | |
| 106 | STATIC_ASSERT(kArrayIndexLengthBits > 0); |
| 107 | STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); |
| 108 | |
| 109 | class ArrayIndexValueBits |
| 110 | : public BitField<unsigned int, kNofHashBitFields, kArrayIndexValueBits> { |
| 111 | }; // NOLINT |
| 112 | class ArrayIndexLengthBits |
| 113 | : public BitField<unsigned int, kNofHashBitFields + kArrayIndexValueBits, |
| 114 | kArrayIndexLengthBits> {}; // NOLINT |
| 115 | |
| 116 | // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we |
| 117 | // could use a mask to test if the length of string is less than or equal to |
| 118 | // kMaxCachedArrayIndexLength. |
| 119 | static_assert(base::bits::IsPowerOfTwo(kMaxCachedArrayIndexLength + 1), |
| 120 | "(kMaxCachedArrayIndexLength + 1) must be power of two" ); |
| 121 | |
| 122 | // When any of these bits is set then the hash field does not contain a cached |
| 123 | // array index. |
| 124 | static const unsigned int kDoesNotContainCachedArrayIndexMask = |
| 125 | (~static_cast<unsigned>(kMaxCachedArrayIndexLength) |
| 126 | << ArrayIndexLengthBits::kShift) | |
| 127 | kIsNotArrayIndexMask; |
| 128 | |
| 129 | // Value of empty hash field indicating that the hash is not computed. |
| 130 | static const int kEmptyHashField = |
| 131 | kIsNotArrayIndexMask | kHashNotComputedMask; |
| 132 | |
| 133 | protected: |
| 134 | static inline bool IsHashFieldComputed(uint32_t field); |
| 135 | |
| 136 | OBJECT_CONSTRUCTORS(Name, HeapObject); |
| 137 | }; |
| 138 | |
| 139 | // ES6 symbols. |
| 140 | class Symbol : public Name { |
| 141 | public: |
| 142 | // [name]: The print name of a symbol, or undefined if none. |
| 143 | DECL_ACCESSORS(name, Object) |
| 144 | |
| 145 | DECL_INT_ACCESSORS(flags) |
| 146 | |
| 147 | // [is_private]: Whether this is a private symbol. Private symbols can only |
| 148 | // be used to designate own properties of objects. |
| 149 | DECL_BOOLEAN_ACCESSORS(is_private) |
| 150 | |
| 151 | // [is_well_known_symbol]: Whether this is a spec-defined well-known symbol, |
| 152 | // or not. Well-known symbols do not throw when an access check fails during |
| 153 | // a load. |
| 154 | DECL_BOOLEAN_ACCESSORS(is_well_known_symbol) |
| 155 | |
| 156 | // [is_interesting_symbol]: Whether this is an "interesting symbol", which |
| 157 | // is a well-known symbol like @@toStringTag that's often looked up on |
| 158 | // random objects but is usually not present. See Name::IsInterestingSymbol() |
| 159 | // for a detailed description. |
| 160 | DECL_BOOLEAN_ACCESSORS(is_interesting_symbol) |
| 161 | |
| 162 | // [is_public]: Whether this is a symbol created by Symbol.for. Calling |
| 163 | // Symbol.keyFor on such a symbol simply needs to return the attached name. |
| 164 | DECL_BOOLEAN_ACCESSORS(is_public) |
| 165 | |
| 166 | // [is_private_name]: Whether this is a private name. Private names |
| 167 | // are the same as private symbols except they throw on missing |
| 168 | // property access. |
| 169 | // |
| 170 | // This also sets the is_private bit. |
| 171 | inline bool is_private_name() const; |
| 172 | inline void set_is_private_name(); |
| 173 | |
| 174 | DECL_CAST(Symbol) |
| 175 | |
| 176 | // Dispatched behavior. |
| 177 | DECL_PRINTER(Symbol) |
| 178 | DECL_VERIFIER(Symbol) |
| 179 | |
| 180 | DEFINE_FIELD_OFFSET_CONSTANTS(Name::kHeaderSize, |
| 181 | TORQUE_GENERATED_SYMBOL_FIELDS) |
| 182 | |
| 183 | // Flags layout. |
| 184 | #define FLAGS_BIT_FIELDS(V, _) \ |
| 185 | V(IsPrivateBit, bool, 1, _) \ |
| 186 | V(IsWellKnownSymbolBit, bool, 1, _) \ |
| 187 | V(IsPublicBit, bool, 1, _) \ |
| 188 | V(IsInterestingSymbolBit, bool, 1, _) \ |
| 189 | V(IsPrivateNameBit, bool, 1, _) |
| 190 | |
| 191 | DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS) |
| 192 | #undef FLAGS_BIT_FIELDS |
| 193 | |
| 194 | using BodyDescriptor = FixedBodyDescriptor<kNameOffset, kSize, kSize>; |
| 195 | |
| 196 | void SymbolShortPrint(std::ostream& os); |
| 197 | |
| 198 | private: |
| 199 | const char* PrivateSymbolToName() const; |
| 200 | |
| 201 | // TODO(cbruni): remove once the new maptracer is in place. |
| 202 | friend class Name; // For PrivateSymbolToName. |
| 203 | |
| 204 | OBJECT_CONSTRUCTORS(Symbol, Name); |
| 205 | }; |
| 206 | |
| 207 | } // namespace internal |
| 208 | } // namespace v8 |
| 209 | |
| 210 | #include "src/objects/object-macros-undef.h" |
| 211 | |
| 212 | #endif // V8_OBJECTS_NAME_H_ |
| 213 | |