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
15namespace v8 {
16namespace 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.
20class 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 kHeaderSize = 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.
140class 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