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