291cdbe19076739d7bef198e9b678285d101dc77
[WebKit-https.git] / Source / JavaScriptCore / runtime / Identifier.h
1 /*
2  *  Copyright (C) 2003, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Library General Public License
15  *  along with this library; see the file COPYING.LIB.  If not, write to
16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  *  Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #ifndef Identifier_h
22 #define Identifier_h
23
24 #include "VM.h"
25 #include <wtf/Optional.h>
26 #include <wtf/ThreadSpecific.h>
27 #include <wtf/WTFThreadData.h>
28 #include <wtf/text/CString.h>
29 #include <wtf/text/WTFString.h>
30
31 namespace JSC {
32
33 class ExecState;
34
35 ALWAYS_INLINE bool isIndex(uint32_t index)
36 {
37     return index != 0xFFFFFFFFU;
38 }
39
40 template <typename CharType>
41 ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length)
42 {
43     // An empty string is not a number.
44     if (!length)
45         return Nullopt;
46
47     // Get the first character, turning it into a digit.
48     uint32_t value = characters[0] - '0';
49     if (value > 9)
50         return Nullopt;
51
52     // Check for leading zeros. If the first characher is 0, then the
53     // length of the string must be one - e.g. "042" is not equal to "42".
54     if (!value && length > 1)
55         return Nullopt;
56
57     while (--length) {
58         // Multiply value by 10, checking for overflow out of 32 bits.
59         if (value > 0xFFFFFFFFU / 10)
60             return Nullopt;
61         value *= 10;
62
63         // Get the next character, turning it into a digit.
64         uint32_t newValue = *(++characters) - '0';
65         if (newValue > 9)
66             return Nullopt;
67
68         // Add in the old value, checking for overflow out of 32 bits.
69         newValue += value;
70         if (newValue < value)
71             return Nullopt;
72         value = newValue;
73     }
74
75     if (!isIndex(value))
76         return Nullopt;
77     return value;
78 }
79
80 ALWAYS_INLINE Optional<uint32_t> parseIndex(StringImpl& impl)
81 {
82     if (impl.is8Bit())
83         return parseIndex(impl.characters8(), impl.length());
84     return parseIndex(impl.characters16(), impl.length());
85 }
86
87 class Identifier {
88     friend class Structure;
89 public:
90     Identifier() { }
91     enum EmptyIdentifierFlag { EmptyIdentifier };
92     Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtomic()); }
93
94     const String& string() const { return m_string; }
95     AtomicStringImpl* impl() const { return static_cast<AtomicStringImpl*>(m_string.impl()); }
96
97     int length() const { return m_string.length(); }
98
99     CString ascii() const { return m_string.ascii(); }
100     CString utf8() const { return m_string.utf8(); }
101
102     // There's 2 functions to construct Identifier from string, (1) fromString and (2) fromUid.
103     // They have different meanings in keeping or discarding symbol-ness of strings.
104     // (1): fromString
105     // Just construct Identifier from string. String held by Identifier is always atomized.
106     // Symbol-ness of StringImpl*, which represents that the string is inteded to be used for ES6 Symbols, is discarded.
107     // So a constructed Identifier never represents a symbol.
108     // (2): fromUid
109     // `StringImpl* uid` represents ether String or Symbol property.
110     // fromUid keeps symbol-ness of provided StringImpl* while fromString discards it.
111     // Use fromUid when constructing Identifier from StringImpl* which may represent symbols.
112
113     // Only to be used with string literals.
114     template<unsigned charactersCount>
115     static Identifier fromString(VM*, const char (&characters)[charactersCount]);
116     template<unsigned charactersCount>
117     static Identifier fromString(ExecState*, const char (&characters)[charactersCount]);
118     static Identifier fromString(VM*, const LChar*, int length);
119     static Identifier fromString(VM*, const UChar*, int length);
120     static Identifier fromString(VM*, const String&);
121     static Identifier fromString(ExecState*, AtomicStringImpl*);
122     static Identifier fromString(ExecState*, const AtomicString&);
123     static Identifier fromString(ExecState*, const String&);
124     static Identifier fromString(ExecState*, const char*);
125
126     static Identifier fromUid(VM*, StringImpl* uid);
127     static Identifier fromUid(ExecState*, StringImpl* uid);
128     static Identifier fromUid(const PrivateName&);
129
130     static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
131
132     JS_EXPORT_PRIVATE static Identifier from(ExecState*, unsigned y);
133     JS_EXPORT_PRIVATE static Identifier from(ExecState*, int y);
134     static Identifier from(ExecState*, double y);
135     static Identifier from(VM*, unsigned y);
136     static Identifier from(VM*, int y);
137     static Identifier from(VM*, double y);
138
139     bool isNull() const { return m_string.isNull(); }
140     bool isEmpty() const { return m_string.isEmpty(); }
141     bool isSymbol() const { return !isNull() && impl()->isSymbol(); }
142
143     friend bool operator==(const Identifier&, const Identifier&);
144     friend bool operator!=(const Identifier&, const Identifier&);
145
146     friend bool operator==(const Identifier&, const LChar*);
147     friend bool operator==(const Identifier&, const char*);
148     friend bool operator!=(const Identifier&, const LChar*);
149     friend bool operator!=(const Identifier&, const char*);
150
151     static bool equal(const StringImpl*, const LChar*);
152     static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
153     static bool equal(const StringImpl*, const LChar*, unsigned length);
154     static bool equal(const StringImpl*, const UChar*, unsigned length);
155     static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
156
157     // Only to be used with string literals.
158     JS_EXPORT_PRIVATE static Ref<StringImpl> add(VM*, const char*);
159     JS_EXPORT_PRIVATE static Ref<StringImpl> add(ExecState*, const char*);
160
161     void dump(PrintStream&) const;
162
163 private:
164     String m_string;
165
166     // Only to be used with string literals.
167     template<unsigned charactersCount>
168     Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtomic()); }
169
170     Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
171     Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
172     Identifier(ExecState*, AtomicStringImpl*);
173     Identifier(ExecState*, const AtomicString&);
174     Identifier(VM* vm, const String& string) : m_string(add(vm, string.impl())) { ASSERT(m_string.impl()->isAtomic()); }
175     Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtomic()); }
176
177     enum UniqueIdentifierFlag { UniqueIdentifier };
178     Identifier(UniqueIdentifierFlag, StringImpl* uid) : m_string(uid) { ASSERT(m_string.impl()->isSymbol()); }
179
180     template <typename CharType>
181     ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
182
183     static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
184     static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
185
186     template <typename T> static Ref<StringImpl> add(VM*, const T*, int length);
187     static Ref<StringImpl> add8(VM*, const UChar*, int length);
188     template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
189
190     static Ref<StringImpl> add(ExecState*, StringImpl*);
191     static Ref<StringImpl> add(VM*, StringImpl*);
192
193 #ifndef NDEBUG
194     JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(ExecState*);
195     JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(VM*);
196 #else
197     JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(ExecState*);
198     JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(VM*);
199 #endif
200 };
201
202 template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
203 {
204     ASSERT(maxSingleCharacterString == 0xff);
205     return true;
206 }
207
208 template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
209 {
210     return (c <= maxSingleCharacterString);
211 }
212
213 template <typename T>
214 Ref<StringImpl> Identifier::add(VM* vm, const T* s, int length)
215 {
216     if (length == 1) {
217         T c = s[0];
218         if (canUseSingleCharacterString(c))
219             return *vm->smallStrings.singleCharacterStringRep(c);
220     }
221     if (!length)
222         return *StringImpl::empty();
223
224     return *AtomicStringImpl::add(s, length);
225 }
226
227 inline bool operator==(const Identifier& a, const Identifier& b)
228 {
229     return Identifier::equal(a, b);
230 }
231
232 inline bool operator!=(const Identifier& a, const Identifier& b)
233 {
234     return !Identifier::equal(a, b);
235 }
236
237 inline bool operator==(const Identifier& a, const LChar* b)
238 {
239     return Identifier::equal(a, b);
240 }
241
242 inline bool operator==(const Identifier& a, const char* b)
243 {
244     return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
245 }
246
247 inline bool operator!=(const Identifier& a, const LChar* b)
248 {
249     return !Identifier::equal(a, b);
250 }
251
252 inline bool operator!=(const Identifier& a, const char* b)
253 {
254     return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
255 }
256
257 inline bool Identifier::equal(const StringImpl* r, const LChar* s)
258 {
259     return WTF::equal(r, s);
260 }
261
262 inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
263 {
264     return WTF::equal(r, s, length);
265 }
266
267 inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
268 {
269     return WTF::equal(r, s, length);
270 }
271
272 ALWAYS_INLINE Optional<uint32_t> parseIndex(const Identifier& identifier)
273 {
274     AtomicStringImpl* uid = identifier.impl();
275     if (!uid)
276         return Nullopt;
277     if (uid->isSymbol())
278         return Nullopt;
279     return parseIndex(*uid);
280 }
281
282 struct IdentifierRepHash : PtrHash<RefPtr<StringImpl>> {
283     static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingSymbolAwareHash(); }
284     static unsigned hash(StringImpl* key) { return key->existingSymbolAwareHash(); }
285 };
286
287 struct IdentifierMapIndexHashTraits : HashTraits<int> {
288     static int emptyValue() { return std::numeric_limits<int>::max(); }
289     static const bool emptyValueIsZero = false;
290 };
291
292 typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
293 typedef HashMap<StringImpl*, int, IdentifierRepHash, HashTraits<StringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
294
295 } // namespace JSC
296
297 namespace WTF {
298
299 template <> struct VectorTraits<JSC::Identifier> : SimpleClassVectorTraits { };
300
301 } // namespace WTF
302
303 #endif // Identifier_h