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