]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
93a37866 | 2 | * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. |
9dae56ea A |
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 | ||
93a37866 | 24 | #include "VM.h" |
6fe7ccc8 | 25 | #include <wtf/ThreadSpecific.h> |
6fe7ccc8 | 26 | #include <wtf/WTFThreadData.h> |
14957cd0 | 27 | #include <wtf/text/CString.h> |
93a37866 | 28 | #include <wtf/text/WTFString.h> |
9dae56ea A |
29 | |
30 | namespace JSC { | |
31 | ||
32 | class ExecState; | |
33 | ||
34 | class Identifier { | |
35 | friend class Structure; | |
36 | public: | |
37 | Identifier() { } | |
93a37866 A |
38 | enum EmptyIdentifierFlag { EmptyIdentifier }; |
39 | Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { } | |
9dae56ea | 40 | |
93a37866 A |
41 | // Only to be used with string literals. |
42 | template<unsigned charactersCount> | |
43 | Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { } | |
44 | template<unsigned charactersCount> | |
45 | Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { } | |
9dae56ea | 46 | |
93a37866 A |
47 | Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { } |
48 | Identifier(ExecState* exec, const String& s) : m_string(add(exec, s.impl())) { } | |
9dae56ea | 49 | |
93a37866 A |
50 | Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { } |
51 | Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { } | |
52 | Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { } | |
53 | Identifier(VM* vm, const String& s) : m_string(add(vm, s.impl())) { } | |
54 | ||
55 | const String& string() const { return m_string; } | |
14957cd0 | 56 | StringImpl* impl() const { return m_string.impl(); } |
9dae56ea | 57 | |
14957cd0 A |
58 | const UChar* characters() const { return m_string.characters(); } |
59 | int length() const { return m_string.length(); } | |
9dae56ea | 60 | |
14957cd0 | 61 | CString ascii() const { return m_string.ascii(); } |
6fe7ccc8 | 62 | |
93a37866 | 63 | static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); } |
6fe7ccc8 A |
64 | |
65 | JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y); | |
66 | JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y); | |
4e4e5a6f | 67 | static Identifier from(ExecState* exec, double y); |
93a37866 A |
68 | static Identifier from(VM*, unsigned y); |
69 | static Identifier from(VM*, int y); | |
70 | static Identifier from(VM*, double y); | |
14957cd0 A |
71 | |
72 | bool isNull() const { return m_string.isNull(); } | |
73 | bool isEmpty() const { return m_string.isEmpty(); } | |
9dae56ea A |
74 | |
75 | friend bool operator==(const Identifier&, const Identifier&); | |
76 | friend bool operator!=(const Identifier&, const Identifier&); | |
77 | ||
6fe7ccc8 | 78 | friend bool operator==(const Identifier&, const LChar*); |
9dae56ea | 79 | friend bool operator==(const Identifier&, const char*); |
6fe7ccc8 | 80 | friend bool operator!=(const Identifier&, const LChar*); |
9dae56ea A |
81 | friend bool operator!=(const Identifier&, const char*); |
82 | ||
6fe7ccc8 A |
83 | static bool equal(const StringImpl*, const LChar*); |
84 | static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); }; | |
85 | static bool equal(const StringImpl*, const LChar*, unsigned length); | |
14957cd0 A |
86 | static bool equal(const StringImpl*, const UChar*, unsigned length); |
87 | static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); } | |
9dae56ea | 88 | |
93a37866 A |
89 | // Only to be used with string literals. |
90 | static PassRefPtr<StringImpl> add(VM*, const char*); | |
91 | JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*); | |
9dae56ea A |
92 | |
93 | private: | |
93a37866 | 94 | String m_string; |
6fe7ccc8 A |
95 | |
96 | template <typename CharType> | |
97 | ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok); | |
98 | ||
14957cd0 | 99 | static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); } |
6fe7ccc8 | 100 | static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); } |
9dae56ea | 101 | |
93a37866 A |
102 | template <typename T> static PassRefPtr<StringImpl> add(VM*, const T*, int length); |
103 | static PassRefPtr<StringImpl> add8(VM*, const UChar*, int length); | |
6fe7ccc8 | 104 | template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T); |
9dae56ea | 105 | |
14957cd0 | 106 | static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r) |
9dae56ea | 107 | { |
9dae56ea | 108 | #ifndef NDEBUG |
4e4e5a6f | 109 | checkCurrentIdentifierTable(exec); |
9dae56ea | 110 | #endif |
4e4e5a6f | 111 | if (r->isIdentifier()) |
9dae56ea | 112 | return r; |
9dae56ea A |
113 | return addSlowCase(exec, r); |
114 | } | |
93a37866 | 115 | static PassRefPtr<StringImpl> add(VM* vm, StringImpl* r) |
9dae56ea | 116 | { |
9dae56ea | 117 | #ifndef NDEBUG |
93a37866 | 118 | checkCurrentIdentifierTable(vm); |
9dae56ea | 119 | #endif |
4e4e5a6f | 120 | if (r->isIdentifier()) |
9dae56ea | 121 | return r; |
93a37866 | 122 | return addSlowCase(vm, r); |
9dae56ea A |
123 | } |
124 | ||
6fe7ccc8 | 125 | JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r); |
93a37866 | 126 | JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(VM*, StringImpl* r); |
9dae56ea | 127 | |
6fe7ccc8 | 128 | JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(ExecState*); |
93a37866 | 129 | JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(VM*); |
6fe7ccc8 A |
130 | }; |
131 | ||
132 | template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar) | |
133 | { | |
134 | ASSERT(maxSingleCharacterString == 0xff); | |
135 | return true; | |
136 | } | |
137 | ||
138 | template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c) | |
139 | { | |
140 | return (c <= maxSingleCharacterString); | |
141 | } | |
142 | ||
143 | template <typename T> | |
144 | struct CharBuffer { | |
145 | const T* s; | |
146 | unsigned int length; | |
9dae56ea A |
147 | }; |
148 | ||
6fe7ccc8 A |
149 | template <typename T> |
150 | struct IdentifierCharBufferTranslator { | |
151 | static unsigned hash(const CharBuffer<T>& buf) | |
152 | { | |
93a37866 | 153 | return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); |
6fe7ccc8 A |
154 | } |
155 | ||
156 | static bool equal(StringImpl* str, const CharBuffer<T>& buf) | |
157 | { | |
158 | return Identifier::equal(str, buf.s, buf.length); | |
159 | } | |
160 | ||
161 | static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash) | |
162 | { | |
163 | T* d; | |
164 | StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef(); | |
165 | for (unsigned i = 0; i != buf.length; i++) | |
166 | d[i] = buf.s[i]; | |
167 | r->setHash(hash); | |
168 | location = r; | |
169 | } | |
170 | }; | |
171 | ||
172 | template <typename T> | |
93a37866 | 173 | PassRefPtr<StringImpl> Identifier::add(VM* vm, const T* s, int length) |
6fe7ccc8 A |
174 | { |
175 | if (length == 1) { | |
176 | T c = s[0]; | |
177 | if (canUseSingleCharacterString(c)) | |
93a37866 | 178 | return add(vm, vm->smallStrings.singleCharacterStringRep(c)); |
6fe7ccc8 A |
179 | } |
180 | ||
181 | if (!length) | |
182 | return StringImpl::empty(); | |
93a37866 A |
183 | CharBuffer<T> buf = { s, static_cast<unsigned>(length) }; |
184 | HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf); | |
6fe7ccc8 A |
185 | |
186 | // If the string is newly-translated, then we need to adopt it. | |
187 | // The boolean in the pair tells us if that is so. | |
188 | return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; | |
189 | } | |
190 | ||
9dae56ea A |
191 | inline bool operator==(const Identifier& a, const Identifier& b) |
192 | { | |
193 | return Identifier::equal(a, b); | |
194 | } | |
195 | ||
196 | inline bool operator!=(const Identifier& a, const Identifier& b) | |
197 | { | |
198 | return !Identifier::equal(a, b); | |
199 | } | |
200 | ||
6fe7ccc8 | 201 | inline bool operator==(const Identifier& a, const LChar* b) |
9dae56ea A |
202 | { |
203 | return Identifier::equal(a, b); | |
204 | } | |
205 | ||
6fe7ccc8 A |
206 | inline bool operator==(const Identifier& a, const char* b) |
207 | { | |
208 | return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); | |
209 | } | |
210 | ||
211 | inline bool operator!=(const Identifier& a, const LChar* b) | |
9dae56ea A |
212 | { |
213 | return !Identifier::equal(a, b); | |
214 | } | |
215 | ||
6fe7ccc8 A |
216 | inline bool operator!=(const Identifier& a, const char* b) |
217 | { | |
218 | return !Identifier::equal(a, reinterpret_cast<const LChar*>(b)); | |
219 | } | |
220 | ||
221 | inline bool Identifier::equal(const StringImpl* r, const LChar* s) | |
222 | { | |
223 | return WTF::equal(r, s); | |
224 | } | |
225 | ||
226 | inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length) | |
227 | { | |
228 | return WTF::equal(r, s, length); | |
229 | } | |
230 | ||
14957cd0 A |
231 | inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length) |
232 | { | |
6fe7ccc8 | 233 | return WTF::equal(r, s, length); |
14957cd0 A |
234 | } |
235 | ||
9dae56ea A |
236 | IdentifierTable* createIdentifierTable(); |
237 | void deleteIdentifierTable(IdentifierTable*); | |
238 | ||
14957cd0 A |
239 | struct IdentifierRepHash : PtrHash<RefPtr<StringImpl> > { |
240 | static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); } | |
241 | static unsigned hash(StringImpl* key) { return key->existingHash(); } | |
242 | }; | |
243 | ||
6fe7ccc8 A |
244 | struct IdentifierMapIndexHashTraits : HashTraits<int> { |
245 | static int emptyValue() { return std::numeric_limits<int>::max(); } | |
246 | static const bool emptyValueIsZero = false; | |
247 | }; | |
248 | ||
249 | typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap; | |
250 | ||
251 | template<typename U, typename V> | |
252 | HashSet<StringImpl*>::AddResult IdentifierTable::add(U value) | |
253 | { | |
254 | HashSet<StringImpl*>::AddResult result = m_table.add<U, V>(value); | |
255 | (*result.iterator)->setIsIdentifier(true); | |
256 | return result; | |
257 | } | |
258 | ||
9dae56ea A |
259 | } // namespace JSC |
260 | ||
93a37866 A |
261 | namespace WTF { |
262 | ||
263 | template <> struct VectorTraits<JSC::Identifier> : SimpleClassVectorTraits { }; | |
264 | ||
265 | } // namespace WTF | |
266 | ||
9dae56ea | 267 | #endif // Identifier_h |