src/3rdparty/webkit/JavaScriptCore/runtime/Identifier.cpp
changeset 0 1918ee327afb
child 30 5dc02b23752f
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*
       
     2  *  Copyright (C) 2003, 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 #include "Identifier.h"
       
    23 
       
    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>
       
    30 
       
    31 namespace JSC {
       
    32 
       
    33 typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable;
       
    34 
       
    35 class IdentifierTable : public FastAllocBase {
       
    36 public:
       
    37     ~IdentifierTable()
       
    38     {
       
    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);
       
    42     }
       
    43     
       
    44     std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value)
       
    45     {
       
    46         std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value);
       
    47         (*result.first)->setIdentifierTable(this);
       
    48         return result;
       
    49     }
       
    50 
       
    51     template<typename U, typename V>
       
    52     std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value)
       
    53     {
       
    54         std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value);
       
    55         (*result.first)->setIdentifierTable(this);
       
    56         return result;
       
    57     }
       
    58 
       
    59     void remove(UString::Rep* r) { m_table.remove(r); }
       
    60 
       
    61     LiteralIdentifierTable& literalTable() { return m_literalTable; }
       
    62 
       
    63 private:
       
    64     HashSet<UString::Rep*> m_table;
       
    65     LiteralIdentifierTable m_literalTable;
       
    66 };
       
    67 
       
    68 IdentifierTable* createIdentifierTable()
       
    69 {
       
    70     return new IdentifierTable;
       
    71 }
       
    72 
       
    73 void deleteIdentifierTable(IdentifierTable* table)
       
    74 {
       
    75     delete table;
       
    76 }
       
    77 
       
    78 bool Identifier::equal(const UString::Rep* r, const char* s)
       
    79 {
       
    80     int length = r->len;
       
    81     const UChar* d = r->data();
       
    82     for (int i = 0; i != length; ++i)
       
    83         if (d[i] != (unsigned char)s[i])
       
    84             return false;
       
    85     return s[length] == 0;
       
    86 }
       
    87 
       
    88 bool Identifier::equal(const UString::Rep* r, const UChar* s, int length)
       
    89 {
       
    90     if (r->len != length)
       
    91         return false;
       
    92     const UChar* d = r->data();
       
    93     for (int i = 0; i != length; ++i)
       
    94         if (d[i] != s[i])
       
    95             return false;
       
    96     return true;
       
    97 }
       
    98 
       
    99 struct CStringTranslator {
       
   100     static unsigned hash(const char* c)
       
   101     {
       
   102         return UString::Rep::computeHash(c);
       
   103     }
       
   104 
       
   105     static bool equal(UString::Rep* r, const char* s)
       
   106     {
       
   107         return Identifier::equal(r, s);
       
   108     }
       
   109 
       
   110     static void translate(UString::Rep*& location, const char* c, unsigned hash)
       
   111     {
       
   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
       
   116         
       
   117         UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
       
   118         r->_hash = hash;
       
   119 
       
   120         location = r;
       
   121     }
       
   122 };
       
   123 
       
   124 PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c)
       
   125 {
       
   126     if (!c) {
       
   127         UString::Rep::null().hash();
       
   128         return &UString::Rep::null();
       
   129     }
       
   130     if (!c[0]) {
       
   131         UString::Rep::empty().hash();
       
   132         return &UString::Rep::empty();
       
   133     }
       
   134     if (!c[1])
       
   135         return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0])));
       
   136 
       
   137     IdentifierTable& identifierTable = *globalData->identifierTable;
       
   138     LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable();
       
   139 
       
   140     const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c);
       
   141     if (iter != literalIdentifierTable.end())
       
   142         return iter->second;
       
   143 
       
   144     pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, CStringTranslator>(c);
       
   145 
       
   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;
       
   149 
       
   150     literalIdentifierTable.add(c, addedString.get());
       
   151 
       
   152     return addedString.release();
       
   153 }
       
   154 
       
   155 PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c)
       
   156 {
       
   157     return add(&exec->globalData(), c);
       
   158 }
       
   159 
       
   160 struct UCharBuffer {
       
   161     const UChar* s;
       
   162     unsigned int length;
       
   163 };
       
   164 
       
   165 struct UCharBufferTranslator {
       
   166     static unsigned hash(const UCharBuffer& buf)
       
   167     {
       
   168         return UString::Rep::computeHash(buf.s, buf.length);
       
   169     }
       
   170 
       
   171     static bool equal(UString::Rep* str, const UCharBuffer& buf)
       
   172     {
       
   173         return Identifier::equal(str, buf.s, buf.length);
       
   174     }
       
   175 
       
   176     static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash)
       
   177     {
       
   178         UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * buf.length));
       
   179         for (unsigned i = 0; i != buf.length; i++)
       
   180             d[i] = buf.s[i];
       
   181         
       
   182         UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef();
       
   183         r->_hash = hash;
       
   184         
       
   185         location = r; 
       
   186     }
       
   187 };
       
   188 
       
   189 PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
       
   190 {
       
   191     if (length == 1) {
       
   192         UChar c = s[0];
       
   193         if (c <= 0xFF)
       
   194             return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
       
   195     }
       
   196     if (!length) {
       
   197         UString::Rep::empty().hash();
       
   198         return &UString::Rep::empty();
       
   199     }
       
   200     UCharBuffer buf = {s, length}; 
       
   201     pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(buf);
       
   202 
       
   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;
       
   206 }
       
   207 
       
   208 PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length)
       
   209 {
       
   210     return add(&exec->globalData(), s, length);
       
   211 }
       
   212 
       
   213 PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r)
       
   214 {
       
   215     ASSERT(!r->identifierTable());
       
   216     if (r->len == 1) {
       
   217         UChar c = r->data()[0];
       
   218         if (c <= 0xFF)
       
   219             r = globalData->smallStrings.singleCharacterStringRep(c);
       
   220             if (r->identifierTable()) {
       
   221 #ifndef NDEBUG
       
   222                 checkSameIdentifierTable(globalData, r);
       
   223 #endif
       
   224                 return r;
       
   225             }
       
   226     }
       
   227     if (!r->len) {
       
   228         UString::Rep::empty().hash();
       
   229         return &UString::Rep::empty();
       
   230     }
       
   231     return *globalData->identifierTable->add(r).first;
       
   232 }
       
   233 
       
   234 PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r)
       
   235 {
       
   236     return addSlowCase(&exec->globalData(), r);
       
   237 }
       
   238 
       
   239 void Identifier::remove(UString::Rep* r)
       
   240 {
       
   241     r->identifierTable()->remove(r);
       
   242 }
       
   243 
       
   244 #ifndef NDEBUG
       
   245 
       
   246 void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep)
       
   247 {
       
   248     ASSERT(rep->identifierTable() == exec->globalData().identifierTable);
       
   249 }
       
   250 
       
   251 void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep)
       
   252 {
       
   253     ASSERT(rep->identifierTable() == globalData->identifierTable);
       
   254 }
       
   255 
       
   256 #else
       
   257 
       
   258 void Identifier::checkSameIdentifierTable(ExecState*, UString::Rep*)
       
   259 {
       
   260 }
       
   261 
       
   262 void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*)
       
   263 {
       
   264 }
       
   265 
       
   266 #endif
       
   267 
       
   268 } // namespace JSC