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 | |