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>
33 typedef HashMap
<const char*, RefPtr
<UString::Rep
>, PtrHash
<const char*> > LiteralIdentifierTable
;
35 class IdentifierTable
{
39 HashSet
<UString::Rep
*>::iterator end
= m_table
.end();
40 for (HashSet
<UString::Rep
*>::iterator iter
= m_table
.begin(); iter
!= end
; ++iter
)
41 (*iter
)->setIdentifierTable(0);
44 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> add(UString::Rep
* value
)
46 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> result
= m_table
.add(value
);
47 (*result
.first
)->setIdentifierTable(this);
51 template<typename U
, typename V
>
52 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> add(U value
)
54 std::pair
<HashSet
<UString::Rep
*>::iterator
, bool> result
= m_table
.add
<U
, V
>(value
);
55 (*result
.first
)->setIdentifierTable(this);
59 void remove(UString::Rep
* r
) { m_table
.remove(r
); }
61 LiteralIdentifierTable
& literalTable() { return m_literalTable
; }
64 HashSet
<UString::Rep
*> m_table
;
65 LiteralIdentifierTable m_literalTable
;
68 IdentifierTable
* createIdentifierTable()
70 return new IdentifierTable
;
73 void deleteIdentifierTable(IdentifierTable
* table
)
78 bool Identifier::equal(const UString::Rep
* r
, const char* s
)
81 const UChar
* d
= r
->data();
82 for (int i
= 0; i
!= length
; ++i
)
83 if (d
[i
] != (unsigned char)s
[i
])
85 return s
[length
] == 0;
88 bool Identifier::equal(const UString::Rep
* r
, const UChar
* s
, int length
)
92 const UChar
* d
= r
->data();
93 for (int i
= 0; i
!= length
; ++i
)
99 struct CStringTranslator
{
100 static unsigned hash(const char* c
)
102 return UString::Rep::computeHash(c
);
105 static bool equal(UString::Rep
* r
, const char* s
)
107 return Identifier::equal(r
, s
);
110 static void translate(UString::Rep
*& location
, const char* c
, unsigned hash
)
112 size_t length
= strlen(c
);
113 UChar
* d
= static_cast<UChar
*>(fastMalloc(sizeof(UChar
) * length
));
114 for (size_t i
= 0; i
!= length
; i
++)
115 d
[i
] = static_cast<unsigned char>(c
[i
]); // use unsigned char to zero-extend instead of sign-extend
117 UString::Rep
* r
= UString::Rep::create(d
, static_cast<int>(length
)).releaseRef();
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
)
178 UChar
* d
= static_cast<UChar
*>(fastMalloc(sizeof(UChar
) * buf
.length
));
179 for (unsigned i
= 0; i
!= buf
.length
; i
++)
182 UString::Rep
* r
= UString::Rep::create(d
, buf
.length
).releaseRef();
189 PassRefPtr
<UString::Rep
> Identifier::add(JSGlobalData
* globalData
, const UChar
* s
, int length
)
194 return add(globalData
, globalData
->smallStrings
.singleCharacterStringRep(c
));
197 UString::Rep::empty().hash();
198 return &UString::Rep::empty();
200 UCharBuffer buf
= {s
, length
};
201 pair
<HashSet
<UString::Rep
*>::iterator
, bool> addResult
= globalData
->identifierTable
->add
<UCharBuffer
, UCharBufferTranslator
>(buf
);
203 // If the string is newly-translated, then we need to adopt it.
204 // The boolean in the pair tells us if that is so.
205 return addResult
.second
? adoptRef(*addResult
.first
) : *addResult
.first
;
208 PassRefPtr
<UString::Rep
> Identifier::add(ExecState
* exec
, const UChar
* s
, int length
)
210 return add(&exec
->globalData(), s
, length
);
213 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(JSGlobalData
* globalData
, UString::Rep
* r
)
215 ASSERT(!r
->identifierTable());
217 UChar c
= r
->data()[0];
219 r
= globalData
->smallStrings
.singleCharacterStringRep(c
);
220 if (r
->identifierTable()) {
222 checkSameIdentifierTable(globalData
, r
);
228 UString::Rep::empty().hash();
229 return &UString::Rep::empty();
231 return *globalData
->identifierTable
->add(r
).first
;
234 PassRefPtr
<UString::Rep
> Identifier::addSlowCase(ExecState
* exec
, UString::Rep
* r
)
236 return addSlowCase(&exec
->globalData(), r
);
239 void Identifier::remove(UString::Rep
* r
)
241 r
->identifierTable()->remove(r
);
246 void Identifier::checkSameIdentifierTable(ExecState
* exec
, UString::Rep
* rep
)
248 ASSERT(rep
->identifierTable() == exec
->globalData().identifierTable
);
251 void Identifier::checkSameIdentifierTable(JSGlobalData
* globalData
, UString::Rep
* rep
)
253 ASSERT(rep
->identifierTable() == globalData
->identifierTable
);
258 void Identifier::checkSameIdentifierTable(ExecState
*, UString::Rep
*)
262 void Identifier::checkSameIdentifierTable(JSGlobalData
*, UString::Rep
*)