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 "NumericStrings.h"
26 #include <new> // for placement new
27 #include <string.h> // for strlen
28 #include <wtf/Assertions.h>
29 #include <wtf/FastMalloc.h>
30 #include <wtf/HashSet.h>
31 #include <wtf/WTFThreadData.h>
32 #include <wtf/text/StringHash.h>
34 using WTF::ThreadSpecific
;
38 IdentifierTable::~IdentifierTable()
40 HashSet
<StringImpl
*>::iterator end
= m_table
.end();
41 for (HashSet
<StringImpl
*>::iterator iter
= m_table
.begin(); iter
!= end
; ++iter
)
42 (*iter
)->setIsIdentifier(false);
44 std::pair
<HashSet
<StringImpl
*>::iterator
, bool> IdentifierTable::add(StringImpl
* value
)
46 std::pair
<HashSet
<StringImpl
*>::iterator
, bool> result
= m_table
.add(value
);
47 (*result
.first
)->setIsIdentifier(true);
50 template<typename U
, typename V
>
51 std::pair
<HashSet
<StringImpl
*>::iterator
, bool> IdentifierTable::add(U value
)
53 std::pair
<HashSet
<StringImpl
*>::iterator
, bool> result
= m_table
.add
<U
, V
>(value
);
54 (*result
.first
)->setIsIdentifier(true);
58 IdentifierTable
* createIdentifierTable()
60 return new IdentifierTable
;
63 void deleteIdentifierTable(IdentifierTable
* table
)
68 bool Identifier::equal(const UString::Rep
* r
, const char* s
)
70 int length
= r
->length();
71 const UChar
* d
= r
->characters();
72 for (int i
= 0; i
!= length
; ++i
)
73 if (d
[i
] != (unsigned char)s
[i
])
75 return s
[length
] == 0;
78 bool Identifier::equal(const UString::Rep
* r
, const UChar
* s
, unsigned length
)
80 if (r
->length() != length
)
82 const UChar
* d
= r
->characters();
83 for (unsigned i
= 0; i
!= length
; ++i
)
89 struct IdentifierCStringTranslator
{
90 static unsigned hash(const char* c
)
92 return UString::Rep::computeHash(c
);
95 static bool equal(UString::Rep
* r
, const char* s
)
97 return Identifier::equal(r
, s
);
100 static void translate(UString::Rep
*& location
, const char* c
, unsigned hash
)
102 size_t length
= strlen(c
);
104 UString::Rep
* r
= UString::Rep::createUninitialized(length
, d
).releaseRef();
105 for (size_t i
= 0; i
!= length
; i
++)
106 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
112 PassRefPtr
<UString::Rep
> Identifier::add(JSGlobalData
* globalData
, const char* c
)
115 return UString::null().rep();
117 return UString::Rep::empty();
119 return add(globalData
, globalData
->smallStrings
.singleCharacterStringRep(static_cast<unsigned char>(c
[0])));
121 IdentifierTable
& identifierTable
= *globalData
->identifierTable
;
122 LiteralIdentifierTable
& literalIdentifierTable
= identifierTable
.literalTable();
124 const LiteralIdentifierTable::iterator
& iter
= literalIdentifierTable
.find(c
);
125 if (iter
!= literalIdentifierTable
.end())
128 pair
<HashSet
<UString::Rep
*>::iterator
, bool> addResult
= identifierTable
.add
<const char*, IdentifierCStringTranslator
>(c
);
130 // If the string is newly-translated, then we need to adopt it.
131 // The boolean in the pair tells us if that is so.
132 RefPtr
<UString::Rep
> addedString
= addResult
.second
? adoptRef(*addResult
.first
) : *addResult
.first
;
134 literalIdentifierTable
.add(c
, addedString
.get());
136 return addedString
.release();
139 PassRefPtr
<UString::Rep
> Identifier::add(ExecState
* exec
, const char* c
)
141 return add(&exec
->globalData(), c
);
149 struct IdentifierUCharBufferTranslator
{
150 static unsigned hash(const UCharBuffer
& buf
)
152 return UString::Rep::computeHash(buf
.s
, buf
.length
);
155 static bool equal(UString::Rep
* str
, const UCharBuffer
& buf
)
157 return Identifier::equal(str
, buf
.s
, buf
.length
);
160 static void translate(UString::Rep
*& location
, const UCharBuffer
& buf
, unsigned hash
)
163 UString::Rep
* r
= UString::Rep::createUninitialized(buf
.length
, d
).releaseRef();
164 for (unsigned i
= 0; i
!= buf
.length
; i
++)
171 PassRefPtr
<UString::Rep
> Identifier::add(JSGlobalData
* globalData
, const UChar
* s
, int length
)
176 return add(globalData
, globalData
->smallStrings
.singleCharacterStringRep(c
));
179 return UString::Rep::empty();
180 UCharBuffer buf
= {s
, length
};
181 pair
<HashSet
<UString::Rep
*>::iterator
, bool> addResult
= globalData
->identifierTable
->add
<UCharBuffer
, IdentifierUCharBufferTranslator
>(buf
);
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
;
188 PassRefPtr
<UString::Rep
> Identifier::add(ExecState
* exec
, const UChar
* s
, int length
)
190 return add(&exec
->globalData(), s
, length
);
193 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(JSGlobalData
* globalData
, UString::Rep
* r
)
195 ASSERT(!r
->isIdentifier());
196 // The empty & null strings are static singletons, and static strings are handled
197 // in ::add() in the header, so we should never get here with a zero length string.
200 if (r
->length() == 1) {
201 UChar c
= r
->characters()[0];
203 r
= globalData
->smallStrings
.singleCharacterStringRep(c
);
204 if (r
->isIdentifier())
208 return *globalData
->identifierTable
->add(r
).first
;
211 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(ExecState
* exec
, UString::Rep
* r
)
213 return addSlowCase(&exec
->globalData(), r
);
216 Identifier
Identifier::from(ExecState
* exec
, unsigned value
)
218 return Identifier(exec
, exec
->globalData().numericStrings
.add(value
));
221 Identifier
Identifier::from(ExecState
* exec
, int value
)
223 return Identifier(exec
, exec
->globalData().numericStrings
.add(value
));
226 Identifier
Identifier::from(ExecState
* exec
, double value
)
228 return Identifier(exec
, exec
->globalData().numericStrings
.add(value
));
233 void Identifier::checkCurrentIdentifierTable(JSGlobalData
* globalData
)
235 // Check the identifier table accessible through the threadspecific matches the
236 // globalData's identifier table.
237 ASSERT_UNUSED(globalData
, globalData
->identifierTable
== wtfThreadData().currentIdentifierTable());
240 void Identifier::checkCurrentIdentifierTable(ExecState
* exec
)
242 checkCurrentIdentifierTable(&exec
->globalData());
247 // These only exists so that our exports are the same for debug and release builds.
248 // This would be an ASSERT_NOT_REACHED(), but we're in NDEBUG only code here!
249 void Identifier::checkCurrentIdentifierTable(JSGlobalData
*) { CRASH(); }
250 void Identifier::checkCurrentIdentifierTable(ExecState
*) { CRASH(); }