// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_NAME_H_ #define V8_OBJECTS_NAME_H_ #include "src/objects.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { // The Name abstract class captures anything that can be used as a property // name, i.e., strings and symbols. All names store a hash value. class Name : public HeapObject { public: // Get and set the hash field of the name. inline uint32_t hash_field(); inline void set_hash_field(uint32_t value); // Tells whether the hash code has been computed. inline bool HasHashCode(); // Returns a hash value used for the property table inline uint32_t Hash(); // Equality operations. inline bool Equals(Name* other); inline static bool Equals(Isolate* isolate, Handle one, Handle two); // Conversion. inline bool AsArrayIndex(uint32_t* index); // An "interesting symbol" is a well-known symbol, like @@toStringTag, // that's often looked up on random objects but is usually not present. // We optimize this by setting a flag on the object's map when such // symbol properties are added, so we can optimize lookups on objects // that don't have the flag. inline bool IsInterestingSymbol() const; // If the name is private, it can only name own properties. inline bool IsPrivate(); // If the name is a private field, it should behave like a private // symbol but also throw on property access miss. inline bool IsPrivateField(); inline bool IsUniqueName() const; static inline bool ContainsCachedArrayIndex(uint32_t hash); // Return a string version of this name that is converted according to the // rules described in ES6 section 9.2.11. V8_WARN_UNUSED_RESULT static MaybeHandle ToFunctionName( Isolate* isolate, Handle name); V8_WARN_UNUSED_RESULT static MaybeHandle ToFunctionName( Isolate* isolate, Handle name, Handle prefix); DECL_CAST(Name) DECL_PRINTER(Name) void NameShortPrint(); int NameShortPrint(Vector str); // Layout description. static const int kHashFieldSlot = HeapObject::kHeaderSize; #if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT static const int kHashFieldOffset = kHashFieldSlot; #else static const int kHashFieldOffset = kHashFieldSlot + kInt32Size; #endif static const int kSize = kHashFieldSlot + kPointerSize; // Mask constant for checking if a name has a computed hash code // and if it is a string that is an array index. The least significant bit // indicates whether a hash code has been computed. If the hash code has // been computed the 2nd bit tells whether the string can be used as an // array index. static const int kHashNotComputedMask = 1; static const int kIsNotArrayIndexMask = 1 << 1; static const int kNofHashBitFields = 2; // Shift constant retrieving hash code from hash field. static const int kHashShift = kNofHashBitFields; // Only these bits are relevant in the hash, since the top two are shifted // out. static const uint32_t kHashBitMask = 0xffffffffu >> kHashShift; // Array index strings this short can keep their index in the hash field. static const int kMaxCachedArrayIndexLength = 7; // Maximum number of characters to consider when trying to convert a string // value into an array index. static const int kMaxArrayIndexSize = 10; // For strings which are array indexes the hash value has the string length // mixed into the hash, mainly to avoid a hash value of zero which would be // the case for the string '0'. 24 bits are used for the array index value. static const int kArrayIndexValueBits = 24; static const int kArrayIndexLengthBits = kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; STATIC_ASSERT(kArrayIndexLengthBits > 0); STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); class ArrayIndexValueBits : public BitField { }; // NOLINT class ArrayIndexLengthBits : public BitField {}; // NOLINT // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we // could use a mask to test if the length of string is less than or equal to // kMaxCachedArrayIndexLength. static_assert(base::bits::IsPowerOfTwo(kMaxCachedArrayIndexLength + 1), "(kMaxCachedArrayIndexLength + 1) must be power of two"); // When any of these bits is set then the hash field does not contain a cached // array index. static const unsigned int kDoesNotContainCachedArrayIndexMask = (~static_cast(kMaxCachedArrayIndexLength) << ArrayIndexLengthBits::kShift) | kIsNotArrayIndexMask; // Value of empty hash field indicating that the hash is not computed. static const int kEmptyHashField = kIsNotArrayIndexMask | kHashNotComputedMask; protected: static inline bool IsHashFieldComputed(uint32_t field); private: DISALLOW_IMPLICIT_CONSTRUCTORS(Name); }; // ES6 symbols. class Symbol : public Name { public: // [name]: The print name of a symbol, or undefined if none. DECL_ACCESSORS(name, Object) DECL_INT_ACCESSORS(flags) // [is_private]: Whether this is a private symbol. Private symbols can only // be used to designate own properties of objects. DECL_BOOLEAN_ACCESSORS(is_private) // [is_well_known_symbol]: Whether this is a spec-defined well-known symbol, // or not. Well-known symbols do not throw when an access check fails during // a load. DECL_BOOLEAN_ACCESSORS(is_well_known_symbol) // [is_interesting_symbol]: Whether this is an "interesting symbol", which // is a well-known symbol like @@toStringTag that's often looked up on // random objects but is usually not present. See Name::IsInterestingSymbol() // for a detailed description. DECL_BOOLEAN_ACCESSORS(is_interesting_symbol) // [is_public]: Whether this is a symbol created by Symbol.for. Calling // Symbol.keyFor on such a symbol simply needs to return the attached name. DECL_BOOLEAN_ACCESSORS(is_public) // [is_private_field]: Whether this is a private field. Private fields // are the same as private symbols except they throw on missing // property access. // // This also sets the is_private bit. inline bool is_private_field() const; inline void set_is_private_field(); DECL_CAST(Symbol) // Dispatched behavior. DECL_PRINTER(Symbol) DECL_VERIFIER(Symbol) // Layout description. static const int kNameOffset = Name::kSize; static const int kFlagsOffset = kNameOffset + kPointerSize; static const int kSize = kFlagsOffset + kPointerSize; // Flags layout. static const int kPrivateBit = 0; static const int kWellKnownSymbolBit = 1; static const int kPublicBit = 2; static const int kInterestingSymbolBit = 3; static const int kPrivateFieldBit = 4; typedef FixedBodyDescriptor BodyDescriptor; // No weak fields. typedef BodyDescriptor BodyDescriptorWeak; void SymbolShortPrint(std::ostream& os); private: const char* PrivateSymbolToName() const; // TODO(cbruni): remove once the new maptracer is in place. friend class Name; // For PrivateSymbolToName. DISALLOW_IMPLICIT_CONSTRUCTORS(Symbol); }; } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_NAME_H_