• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 #include "config.h"
22 
23 #ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC
24 #define ATOMICSTRING_HIDE_GLOBALS 1
25 #endif
26 
27 #include "AtomicString.h"
28 
29 #include "StaticConstructors.h"
30 #include "StringHash.h"
31 #include "ThreadGlobalData.h"
32 #include <wtf/Threading.h>
33 #include <wtf/HashSet.h>
34 
35 #if USE(JSC)
36 #include <runtime/Identifier.h>
37 using JSC::Identifier;
38 using JSC::UString;
39 #endif
40 
41 namespace WebCore {
42 
stringTable()43 static inline HashSet<StringImpl*>& stringTable()
44 {
45     return threadGlobalData().atomicStringTable();
46 }
47 
48 struct CStringTranslator {
hashWebCore::CStringTranslator49     static unsigned hash(const char* c)
50     {
51         return StringImpl::computeHash(c);
52     }
53 
equalWebCore::CStringTranslator54     static bool equal(StringImpl* r, const char* s)
55     {
56         int length = r->length();
57         const UChar* d = r->characters();
58         for (int i = 0; i != length; ++i) {
59             unsigned char c = s[i];
60             if (d[i] != c)
61                 return false;
62         }
63         return s[length] == 0;
64     }
65 
translateWebCore::CStringTranslator66     static void translate(StringImpl*& location, const char* const& c, unsigned hash)
67     {
68         location = new StringImpl(c, strlen(c), hash);
69     }
70 };
71 
operator ==(const AtomicString & a,const char * b)72 bool operator==(const AtomicString& a, const char* b)
73 {
74     StringImpl* impl = a.impl();
75     if ((!impl || !impl->characters()) && !b)
76         return true;
77     if ((!impl || !impl->characters()) || !b)
78         return false;
79     return CStringTranslator::equal(impl, b);
80 }
81 
add(const char * c)82 PassRefPtr<StringImpl> AtomicString::add(const char* c)
83 {
84     if (!c)
85         return 0;
86     if (!*c)
87         return StringImpl::empty();
88     pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<const char*, CStringTranslator>(c);
89     if (!addResult.second)
90         return *addResult.first;
91     return adoptRef(*addResult.first);
92 }
93 
94 struct UCharBuffer {
95     const UChar* s;
96     unsigned length;
97 };
98 
equal(StringImpl * string,const UChar * characters,unsigned length)99 static inline bool equal(StringImpl* string, const UChar* characters, unsigned length)
100 {
101     if (string->length() != length)
102         return false;
103 
104 #if PLATFORM(ARM) || PLATFORM(SH4)
105     const UChar* stringCharacters = string->characters();
106     for (unsigned i = 0; i != length; ++i) {
107         if (*stringCharacters++ != *characters++)
108             return false;
109     }
110     return true;
111 #else
112     /* Do it 4-bytes-at-a-time on architectures where it's safe */
113 
114     const uint32_t* stringCharacters = reinterpret_cast<const uint32_t*>(string->characters());
115     const uint32_t* bufferCharacters = reinterpret_cast<const uint32_t*>(characters);
116 
117     unsigned halfLength = length >> 1;
118     for (unsigned i = 0; i != halfLength; ++i) {
119         if (*stringCharacters++ != *bufferCharacters++)
120             return false;
121     }
122 
123     if (length & 1 &&  *reinterpret_cast<const uint16_t*>(stringCharacters) != *reinterpret_cast<const uint16_t*>(bufferCharacters))
124         return false;
125 
126     return true;
127 #endif
128 }
129 
130 struct UCharBufferTranslator {
hashWebCore::UCharBufferTranslator131     static unsigned hash(const UCharBuffer& buf)
132     {
133         return StringImpl::computeHash(buf.s, buf.length);
134     }
135 
equalWebCore::UCharBufferTranslator136     static bool equal(StringImpl* const& str, const UCharBuffer& buf)
137     {
138         return WebCore::equal(str, buf.s, buf.length);
139     }
140 
translateWebCore::UCharBufferTranslator141     static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash)
142     {
143         location = new StringImpl(buf.s, buf.length, hash);
144     }
145 };
146 
147 struct HashAndCharacters {
148     unsigned hash;
149     const UChar* characters;
150     unsigned length;
151 };
152 
153 struct HashAndCharactersTranslator {
hashWebCore::HashAndCharactersTranslator154     static unsigned hash(const HashAndCharacters& buffer)
155     {
156         ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.length));
157         return buffer.hash;
158     }
159 
equalWebCore::HashAndCharactersTranslator160     static bool equal(StringImpl* const& string, const HashAndCharacters& buffer)
161     {
162         return WebCore::equal(string, buffer.characters, buffer.length);
163     }
164 
translateWebCore::HashAndCharactersTranslator165     static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash)
166     {
167         location = new StringImpl(buffer.characters, buffer.length, hash);
168     }
169 };
170 
add(const UChar * s,int length)171 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length)
172 {
173     if (!s)
174         return 0;
175 
176     if (length == 0)
177         return StringImpl::empty();
178 
179     UCharBuffer buf = { s, length };
180     pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
181 
182     // If the string is newly-translated, then we need to adopt it.
183     // The boolean in the pair tells us if that is so.
184     return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
185 }
186 
add(const UChar * s)187 PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
188 {
189     if (!s)
190         return 0;
191 
192     int length = 0;
193     while (s[length] != UChar(0))
194         length++;
195 
196     if (length == 0)
197         return StringImpl::empty();
198 
199     UCharBuffer buf = {s, length};
200     pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf);
201 
202     // If the string is newly-translated, then we need to adopt it.
203     // The boolean in the pair tells us if that is so.
204     return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
205 }
206 
add(StringImpl * r)207 PassRefPtr<StringImpl> AtomicString::add(StringImpl* r)
208 {
209     if (!r || r->inTable())
210         return r;
211 
212     if (r->length() == 0)
213         return StringImpl::empty();
214 
215     StringImpl* result = *stringTable().add(r).first;
216     if (result == r)
217         r->setInTable();
218     return result;
219 }
220 
remove(StringImpl * r)221 void AtomicString::remove(StringImpl* r)
222 {
223     stringTable().remove(r);
224 }
225 
226 #if USE(JSC)
add(const JSC::Identifier & identifier)227 PassRefPtr<StringImpl> AtomicString::add(const JSC::Identifier& identifier)
228 {
229     if (identifier.isNull())
230         return 0;
231 
232     UString::Rep* string = identifier.ustring().rep();
233     unsigned length = string->size();
234     if (!length)
235         return StringImpl::empty();
236 
237     HashAndCharacters buffer = { string->computedHash(), string->data(), length };
238     pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
239     if (!addResult.second)
240         return *addResult.first;
241     return adoptRef(*addResult.first);
242 }
243 
add(const JSC::UString & ustring)244 PassRefPtr<StringImpl> AtomicString::add(const JSC::UString& ustring)
245 {
246     if (ustring.isNull())
247         return 0;
248 
249     UString::Rep* string = ustring.rep();
250     unsigned length = string->size();
251     if (!length)
252         return StringImpl::empty();
253 
254     HashAndCharacters buffer = { string->hash(), string->data(), length };
255     pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
256     if (!addResult.second)
257         return *addResult.first;
258     return adoptRef(*addResult.first);
259 }
260 
find(const JSC::Identifier & identifier)261 AtomicStringImpl* AtomicString::find(const JSC::Identifier& identifier)
262 {
263     if (identifier.isNull())
264         return 0;
265 
266     UString::Rep* string = identifier.ustring().rep();
267     unsigned length = string->size();
268     if (!length)
269         return static_cast<AtomicStringImpl*>(StringImpl::empty());
270 
271     HashAndCharacters buffer = { string->computedHash(), string->data(), length };
272     HashSet<StringImpl*>::iterator iterator = stringTable().find<HashAndCharacters, HashAndCharactersTranslator>(buffer);
273     if (iterator == stringTable().end())
274         return 0;
275     return static_cast<AtomicStringImpl*>(*iterator);
276 }
277 
operator UString() const278 AtomicString::operator UString() const
279 {
280     return m_string;
281 }
282 #endif
283 
DEFINE_GLOBAL(AtomicString,nullAtom)284 DEFINE_GLOBAL(AtomicString, nullAtom)
285 DEFINE_GLOBAL(AtomicString, emptyAtom, "")
286 DEFINE_GLOBAL(AtomicString, textAtom, "#text")
287 DEFINE_GLOBAL(AtomicString, commentAtom, "#comment")
288 DEFINE_GLOBAL(AtomicString, starAtom, "*")
289 
290 void AtomicString::init()
291 {
292     static bool initialized;
293     if (!initialized) {
294         // Initialization is not thread safe, so this function must be called from the main thread first.
295         ASSERT(isMainThread());
296 
297         // Use placement new to initialize the globals.
298         new ((void*)&nullAtom) AtomicString;
299         new ((void*)&emptyAtom) AtomicString("");
300         new ((void*)&textAtom) AtomicString("#text");
301         new ((void*)&commentAtom) AtomicString("#comment");
302         new ((void*)&starAtom) AtomicString("*");
303 
304         initialized = true;
305     }
306 }
307 
308 }
309