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();