2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
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.
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.
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.
22 #include "Identifier.h"
24 #include "CallFrame.h"
25 #include <new> // for placement new
26 #include <string.h> // for strlen
27 #include <wtf/Assertions.h>
28 #include <wtf/FastMalloc.h>
29 #include <wtf/HashSet.h>
31 using WTF::ThreadSpecific
;
35 typedef HashMap
<const char*, RefPtr
<UString::Rep
>, PtrHash
<const char*> > LiteralIdentifierTable
;
37 class IdentifierTable
: public FastAllocBase
{
41 HashSet
<UString::Rep
*>::iterator end
= m_table
.end();
42 for (HashSet
<UString::Rep
*>::iterator iter
= m_table
.begin(); iter
!= end
; ++iter
)
43 (*iter
)->setIsIdentifier(false);
46 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> add(UString::Rep
* value
)
48 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> result
= m_table
.add(value
);
49 (*result
.first
)->setIsIdentifier(true);
53 template<typename U
, typename V
>
54 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> add(U value
)
56 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> result
= m_table
.add
<U
, V
>(value
);
57 (*result
.first
)->setIsIdentifier(true);
61 void remove(UString::Rep
* r
) { m_table
.remove(r
); }
63 LiteralIdentifierTable
& literalTable() { return m_literalTable
; }
66 HashSet
<UString::Rep
*> m_table
;
67 LiteralIdentifierTable m_literalTable
;
70 IdentifierTable
* createIdentifierTable()
72 return new IdentifierTable
;
75 void deleteIdentifierTable(IdentifierTable
* table
)
80 bool Identifier::equal(const UString::Rep
* r
, const char* s
)
82 int length
= r
->size();
83 const UChar
* d
= r
->data();
84 for (int i
= 0; i
!= length
; ++i
)
85 if (d
[i
] != (unsigned char)s
[i
])
87 return s
[length
] == 0;
90 bool Identifier::equal(const UString::Rep
* r
, const UChar
* s
, int length
)
92 if (r
->size() != length
)
94 const UChar
* d
= r
->data();
95 for (int i
= 0; i
!= length
; ++i
)
101 struct CStringTranslator
{
102 static unsigned hash(const char* c
)
104 return UString::Rep::computeHash(c
);
107 static bool equal(UString::Rep
* r
, const char* s
)
109 return Identifier::equal(r
, s
);
112 static void translate(UString::Rep
*& location
, const char* c
, unsigned hash
)
114 size_t length
= strlen(c
);
116 UString::Rep
* r
= UString::Rep::createUninitialized(length
, d
).releaseRef();
117 for (size_t i
= 0; i
!= length
; i
++)
118 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
124 PassRefPtr
<UString::Rep
> Identifier::add(JSGlobalData
* globalData
, const char* c
)
127 UString::Rep::null().hash();
128 return &UString::Rep::null();
131 UString::Rep::empty().hash();
132 return &UString::Rep::empty();
135 return add(globalData
, globalData
->smallStrings
.singleCharacterStringRep(static_cast<unsigned char>(c
[0])));
137 IdentifierTable
& identifierTable
= *globalData
->identifierTable
;
138 LiteralIdentifierTable
& literalIdentifierTable
= identifierTable
.literalTable();
140 const LiteralIdentifierTable::iterator
& iter
= literalIdentifierTable
.find(c
);
141 if (iter
!= literalIdentifierTable
.end())
144 pair
<HashSet
<UString::Rep
*>::iterator
, bool> addResult
= identifierTable
.add
<const char*, CStringTranslator
>(c
);
146 // If the string is newly-translated, then we need to adopt it.
147 // The boolean in the pair tells us if that is so.
148 RefPtr
<UString::Rep
> addedString
= addResult
.second
? adoptRef(*addResult
.first
) : *addResult
.first
;
150 literalIdentifierTable
.add(c
, addedString
.get());
152 return addedString
.release();
155 PassRefPtr
<UString::Rep
> Identifier::add(ExecState
* exec
, const char* c
)
157 return add(&exec
->globalData(), c
);
165 struct UCharBufferTranslator
{
166 static unsigned hash(const UCharBuffer
& buf
)
168 return UString::Rep::computeHash(buf
.s
, buf
.length
);
171 static bool equal(UString::Rep
* str
, const UCharBuffer
& buf
)
173 return Identifier::equal(str
, buf
.s
, buf
.length
);
176 static void translate(UString::Rep
*& location
, const UCharBuffer
& buf
, unsigned hash
)
179 UString::Rep
* r
= UString::Rep::createUninitialized(buf
.length
, d
).releaseRef();
180 for (unsigned i
= 0; i
!= buf
.length
; i
++)
187 PassRefPtr
<UString::Rep
> Identifier::add(JSGlobalData
* globalData
, const UChar
* s
, int length
)
192 return add(globalData
, globalData
->smallStrings
.singleCharacterStringRep(c
));
195 UString::Rep::empty().hash();
196 return &UString::Rep::empty();
198 UCharBuffer buf
= {s
, length
};
199 pair
<HashSet
<UString::Rep
*>::iterator
, bool> addResult
= globalData
->identifierTable
->add
<UCharBuffer
, UCharBufferTranslator
>(buf
);
201 // If the string is newly-translated, then we need to adopt it.
202 // The boolean in the pair tells us if that is so.
203 return addResult
.second
? adoptRef(*addResult
.first
) : *addResult
.first
;
206 PassRefPtr
<UString::Rep
> Identifier::add(ExecState
* exec
, const UChar
* s
, int length
)
208 return add(&exec
->globalData(), s
, length
);
211 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(JSGlobalData
* globalData
, UString::Rep
* r
)
213 ASSERT(!r
->isIdentifier());
214 if (r
->size() == 1) {
215 UChar c
= r
->data()[0];
217 r
= globalData
->smallStrings
.singleCharacterStringRep(c
);
218 if (r
->isIdentifier()) {
220 checkSameIdentifierTable(globalData
, r
);
226 UString::Rep::empty().hash();
227 return &UString::Rep::empty();
229 return *globalData
->identifierTable
->add(r
).first
;
232 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(ExecState
* exec
, UString::Rep
* r
)
234 return addSlowCase(&exec
->globalData(), r
);
237 void Identifier::remove(UString::Rep
* r
)
239 currentIdentifierTable()->remove(r
);
244 void Identifier::checkSameIdentifierTable(ExecState
* exec
, UString::Rep
*)
246 ASSERT_UNUSED(exec
, exec
->globalData().identifierTable
== currentIdentifierTable());
249 void Identifier::checkSameIdentifierTable(JSGlobalData
* globalData
, UString::Rep
*)
251 ASSERT_UNUSED(globalData
, globalData
->identifierTable
== currentIdentifierTable());
256 void Identifier::checkSameIdentifierTable(ExecState
*, UString::Rep
*)
260 void Identifier::checkSameIdentifierTable(JSGlobalData
*, UString::Rep
*)
266 ThreadSpecific
<ThreadIdentifierTableData
>* g_identifierTableSpecific
= 0;
267 ThreadIdentifierTableData
* g_identifierTableMain
= 0;
269 #if ENABLE(JSC_MULTIPLE_THREADS)
271 pthread_once_t createIdentifierTableSpecificOnce
= PTHREAD_ONCE_INIT
;
272 static void createIdentifierTableSpecificCallback()
274 ASSERT(!g_identifierTableSpecific
);
275 g_identifierTableSpecific
= new ThreadSpecific
<ThreadIdentifierTableData
>();
276 ASSERT(!g_identifierTableMain
);
277 g_identifierTableMain
= new ThreadIdentifierTableData();
279 void createIdentifierTableSpecific()
281 pthread_once(&createIdentifierTableSpecificOnce
, createIdentifierTableSpecificCallback
);
282 ASSERT(g_identifierTableSpecific
);
283 ASSERT(g_identifierTableMain
);
288 void createIdentifierTableSpecific()
290 ASSERT(!g_identifierTableSpecific
);
291 g_identifierTableSpecific
= new ThreadSpecific
<ThreadIdentifierTableData
>();
292 ASSERT(!g_identifierTableMain
);
293 g_identifierTableMain
= new ThreadIdentifierTableData();