1/*
2 * Copyright (C) 2003-2019 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#pragma once
22
23#include "PrivateName.h"
24#include "VM.h"
25#include <wtf/Optional.h>
26#include <wtf/text/CString.h>
27#include <wtf/text/UniquedStringImpl.h>
28#include <wtf/text/WTFString.h>
29
30namespace JSC {
31
32class CallFrame;
33
34ALWAYS_INLINE bool isIndex(uint32_t index)
35{
36 return index != 0xFFFFFFFFU;
37}
38
39template <typename CharType>
40ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length)
41{
42 // An empty string is not a number.
43 if (!length)
44 return WTF::nullopt;
45
46 // Get the first character, turning it into a digit.
47 uint32_t value = characters[0] - '0';
48 if (value > 9)
49 return WTF::nullopt;
50
51 // Check for leading zeros. If the first characher is 0, then the
52 // length of the string must be one - e.g. "042" is not equal to "42".
53 if (!value && length > 1)
54 return WTF::nullopt;
55
56 while (--length) {
57 // Multiply value by 10, checking for overflow out of 32 bits.
58 if (value > 0xFFFFFFFFU / 10)
59 return WTF::nullopt;
60 value *= 10;
61
62 // Get the next character, turning it into a digit.
63 uint32_t newValue = *(++characters) - '0';
64 if (newValue > 9)
65 return WTF::nullopt;
66
67 // Add in the old value, checking for overflow out of 32 bits.
68 newValue += value;
69 if (newValue < value)
70 return WTF::nullopt;
71 value = newValue;
72 }
73
74 if (!isIndex(value))
75 return WTF::nullopt;
76 return value;
77}
78
79ALWAYS_INLINE Optional<uint32_t> parseIndex(StringImpl& impl)
80{
81 if (impl.is8Bit())
82 return parseIndex(impl.characters8(), impl.length());
83 return parseIndex(impl.characters16(), impl.length());
84}
85
86class Identifier {
87 friend class Structure;
88public:
89 Identifier() { }
90 enum EmptyIdentifierFlag { EmptyIdentifier };
91 Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtom()); }
92
93 const String& string() const { return m_string; }
94 UniquedStringImpl* impl() const { return static_cast<UniquedStringImpl*>(m_string.impl()); }
95
96 int length() const { return m_string.length(); }
97
98 CString ascii() const { return m_string.ascii(); }
99 CString utf8() const { return m_string.utf8(); }
100
101 // There's 2 functions to construct Identifier from string, (1) fromString and (2) fromUid.
102 // They have different meanings in keeping or discarding symbol-ness of strings.
103 // (1): fromString
104 // Just construct Identifier from string. String held by Identifier is always atomized.
105 // Symbol-ness of StringImpl*, which represents that the string is inteded to be used for ES6 Symbols, is discarded.
106 // So a constructed Identifier never represents a symbol.
107 // (2): fromUid
108 // `StringImpl* uid` represents ether String or Symbol property.
109 // fromUid keeps symbol-ness of provided StringImpl* while fromString discards it.
110 // Use fromUid when constructing Identifier from StringImpl* which may represent symbols.
111
112 // Only to be used with string literals.
113 template<unsigned charactersCount>
114 static Identifier fromString(VM&, const char (&characters)[charactersCount]);
115 static Identifier fromString(VM&, ASCIILiteral);
116 static Identifier fromString(VM&, const LChar*, int length);
117 static Identifier fromString(VM&, const UChar*, int length);
118 static Identifier fromString(VM&, const String&);
119 static Identifier fromString(VM&, AtomStringImpl*);
120 static Identifier fromString(VM&, const AtomString&);
121 static Identifier fromString(VM& vm, SymbolImpl*);
122 static Identifier fromString(VM&, const char*);
123 static Identifier fromString(VM& vm, const Vector<LChar>& characters) { return fromString(vm, characters.data(), characters.size()); }
124
125 static Identifier fromUid(VM&, UniquedStringImpl* uid);
126 static Identifier fromUid(const PrivateName&);
127 static Identifier fromUid(SymbolImpl&);
128
129 static Identifier createLCharFromUChar(VM& vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
130
131 JS_EXPORT_PRIVATE static Identifier from(VM&, unsigned y);
132 JS_EXPORT_PRIVATE static Identifier from(VM&, int y);
133 static Identifier from(VM&, double y);
134
135 bool isNull() const { return m_string.isNull(); }
136 bool isEmpty() const { return m_string.isEmpty(); }
137 bool isSymbol() const { return !isNull() && impl()->isSymbol(); }
138 bool isPrivateName() const { return isSymbol() && static_cast<const SymbolImpl*>(impl())->isPrivate(); }
139
140 friend bool operator==(const Identifier&, const Identifier&);
141 friend bool operator!=(const Identifier&, const Identifier&);
142
143 friend bool operator==(const Identifier&, const LChar*);
144 friend bool operator==(const Identifier&, const char*);
145 friend bool operator!=(const Identifier&, const LChar*);
146 friend bool operator!=(const Identifier&, const char*);
147
148 static bool equal(const StringImpl*, const LChar*);
149 static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
150 static bool equal(const StringImpl*, const LChar*, unsigned length);
151 static bool equal(const StringImpl*, const UChar*, unsigned length);
152 static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
153
154 // Only to be used with string literals.
155 JS_EXPORT_PRIVATE static Ref<StringImpl> add(VM&, const char*);
156
157 void dump(PrintStream&) const;
158
159private:
160 String m_string;
161
162 // Only to be used with string literals.
163 template<unsigned charactersCount>
164 Identifier(VM& vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtom()); }
165
166 Identifier(VM& vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtom()); }
167 Identifier(VM& vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtom()); }
168 Identifier(VM&, AtomStringImpl*);
169 Identifier(VM&, const AtomString&);
170 Identifier(VM& vm, const String& string) : m_string(add(vm, string.impl())) { ASSERT(m_string.impl()->isAtom()); }
171 Identifier(VM& vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtom()); }
172
173 Identifier(SymbolImpl& uid)
174 : m_string(&uid)
175 {
176 }
177
178 template <typename CharType>
179 ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
180
181 static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
182 static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
183
184 template <typename T> static Ref<StringImpl> add(VM&, const T*, int length);
185 static Ref<StringImpl> add8(VM&, const UChar*, int length);
186 template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
187
188 static Ref<StringImpl> add(VM&, StringImpl*);
189
190#ifndef NDEBUG
191 JS_EXPORT_PRIVATE static void checkCurrentAtomStringTable(VM&);
192#else
193 JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomStringTable(VM&);
194#endif
195};
196
197template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
198{
199 ASSERT(maxSingleCharacterString == 0xff);
200 return true;
201}
202
203template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
204{
205 return (c <= maxSingleCharacterString);
206}
207
208template <typename T>
209Ref<StringImpl> Identifier::add(VM& vm, const T* s, int length)
210{
211 if (length == 1) {
212 T c = s[0];
213 if (canUseSingleCharacterString(c))
214 return vm.smallStrings.singleCharacterStringRep(c);
215 }
216 if (!length)
217 return *StringImpl::empty();
218
219 return *AtomStringImpl::add(s, length);
220}
221
222inline bool operator==(const Identifier& a, const Identifier& b)
223{
224 return Identifier::equal(a, b);
225}
226
227inline bool operator!=(const Identifier& a, const Identifier& b)
228{
229 return !Identifier::equal(a, b);
230}
231
232inline bool operator==(const Identifier& a, const LChar* b)
233{
234 return Identifier::equal(a, b);
235}
236
237inline bool operator==(const Identifier& a, const char* b)
238{
239 return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
240}
241
242inline bool operator!=(const Identifier& a, const LChar* b)
243{
244 return !Identifier::equal(a, b);
245}
246
247inline bool operator!=(const Identifier& a, const char* b)
248{
249 return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
250}
251
252inline bool Identifier::equal(const StringImpl* r, const LChar* s)
253{
254 return WTF::equal(r, s);
255}
256
257inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
258{
259 return WTF::equal(r, s, length);
260}
261
262inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
263{
264 return WTF::equal(r, s, length);
265}
266
267ALWAYS_INLINE Optional<uint32_t> parseIndex(const Identifier& identifier)
268{
269 auto uid = identifier.impl();
270 if (!uid)
271 return WTF::nullopt;
272 if (uid->isSymbol())
273 return WTF::nullopt;
274 return parseIndex(*uid);
275}
276
277JSValue identifierToJSValue(VM&, const Identifier&);
278// This will stringify private symbols. When leaking JSValues to
279// non-internal code, make sure to use this function and not the above one.
280JSValue identifierToSafePublicJSValue(VM&, const Identifier&);
281
282// FIXME: It may be better for this to just be a typedef for PtrHash, since PtrHash may be cheaper to
283// compute than loading the StringImpl's hash from memory. That change would also reduce the likelihood of
284// crashes in code that somehow dangled a StringImpl.
285// https://bugs.webkit.org/show_bug.cgi?id=150137
286struct IdentifierRepHash : PtrHash<RefPtr<UniquedStringImpl>> {
287 static unsigned hash(const RefPtr<UniquedStringImpl>& key) { return key->existingSymbolAwareHash(); }
288 static unsigned hash(UniquedStringImpl* key) { return key->existingSymbolAwareHash(); }
289};
290
291struct IdentifierMapIndexHashTraits : HashTraits<int> {
292 static int emptyValue() { return std::numeric_limits<int>::max(); }
293 static constexpr bool emptyValueIsZero = false;
294};
295
296typedef HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> IdentifierSet;
297typedef HashMap<RefPtr<UniquedStringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
298typedef HashMap<UniquedStringImpl*, int, IdentifierRepHash, HashTraits<UniquedStringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
299
300} // namespace JSC
301
302namespace WTF {
303
304template <> struct VectorTraits<JSC::Identifier> : SimpleClassVectorTraits { };
305
306} // namespace WTF
307