JavaScriptCore/runtime/Identifier.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "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>
       
    33 
       
    34 using WTF::ThreadSpecific;
       
    35 
       
    36 namespace JSC {
       
    37 
       
    38 IdentifierTable::~IdentifierTable()
       
    39 {
       
    40     HashSet<StringImpl*>::iterator end = m_table.end();
       
    41     for (HashSet<StringImpl*>::iterator iter = m_table.begin(); iter != end; ++iter)
       
    42         (*iter)->setIsIdentifier(false);
       
    43 }
       
    44 std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(StringImpl* value)
       
    45 {
       
    46     std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add(value);
       
    47     (*result.first)->setIsIdentifier(true);
       
    48     return result;
       
    49 }
       
    50 template<typename U, typename V>
       
    51 std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(U value)
       
    52 {
       
    53     std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add<U, V>(value);
       
    54     (*result.first)->setIsIdentifier(true);
       
    55     return result;
       
    56 }
       
    57 
       
    58 IdentifierTable* createIdentifierTable()
       
    59 {
       
    60     return new IdentifierTable;
       
    61 }
       
    62 
       
    63 void deleteIdentifierTable(IdentifierTable* table)
       
    64 {
       
    65     delete table;
       
    66 }
       
    67 
       
    68 bool Identifier::equal(const UString::Rep* r, const char* s)
       
    69 {
       
    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])
       
    74             return false;
       
    75     return s[length] == 0;
       
    76 }
       
    77 
       
    78 bool Identifier::equal(const UString::Rep* r, const UChar* s, unsigned length)
       
    79 {
       
    80     if (r->length() != length)
       
    81         return false;
       
    82     const UChar* d = r->characters();
       
    83     for (unsigned i = 0; i != length; ++i)
       
    84         if (d[i] != s[i])
       
    85             return false;
       
    86     return true;
       
    87 }
       
    88 
       
    89 struct IdentifierCStringTranslator {
       
    90     static unsigned hash(const char* c)
       
    91     {
       
    92         return UString::Rep::computeHash(c);
       
    93     }
       
    94 
       
    95     static bool equal(UString::Rep* r, const char* s)
       
    96     {
       
    97         return Identifier::equal(r, s);
       
    98     }
       
    99 
       
   100     static void translate(UString::Rep*& location, const char* c, unsigned hash)
       
   101     {
       
   102         size_t length = strlen(c);
       
   103         UChar* d;
       
   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
       
   107         r->setHash(hash);
       
   108         location = r;
       
   109     }
       
   110 };
       
   111 
       
   112 PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c)
       
   113 {
       
   114     if (!c)
       
   115         return UString::null().rep();
       
   116     if (!c[0])
       
   117         return UString::Rep::empty();
       
   118     if (!c[1])
       
   119         return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0])));
       
   120 
       
   121     IdentifierTable& identifierTable = *globalData->identifierTable;
       
   122     LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable();
       
   123 
       
   124     const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c);
       
   125     if (iter != literalIdentifierTable.end())
       
   126         return iter->second;
       
   127 
       
   128     pair<HashSet<UString::Rep*>::iterator, bool> addResult = identifierTable.add<const char*, IdentifierCStringTranslator>(c);
       
   129 
       
   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;
       
   133 
       
   134     literalIdentifierTable.add(c, addedString.get());
       
   135 
       
   136     return addedString.release();
       
   137 }
       
   138 
       
   139 PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c)
       
   140 {
       
   141     return add(&exec->globalData(), c);
       
   142 }
       
   143 
       
   144 struct UCharBuffer {
       
   145     const UChar* s;
       
   146     unsigned int length;
       
   147 };
       
   148 
       
   149 struct IdentifierUCharBufferTranslator {
       
   150     static unsigned hash(const UCharBuffer& buf)
       
   151     {
       
   152         return UString::Rep::computeHash(buf.s, buf.length);
       
   153     }
       
   154 
       
   155     static bool equal(UString::Rep* str, const UCharBuffer& buf)
       
   156     {
       
   157         return Identifier::equal(str, buf.s, buf.length);
       
   158     }
       
   159 
       
   160     static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash)
       
   161     {
       
   162         UChar* d;
       
   163         UString::Rep* r = UString::Rep::createUninitialized(buf.length, d).releaseRef();
       
   164         for (unsigned i = 0; i != buf.length; i++)
       
   165             d[i] = buf.s[i];
       
   166         r->setHash(hash);
       
   167         location = r; 
       
   168     }
       
   169 };
       
   170 
       
   171 PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
       
   172 {
       
   173     if (length == 1) {
       
   174         UChar c = s[0];
       
   175         if (c <= 0xFF)
       
   176             return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
       
   177     }
       
   178     if (!length)
       
   179         return UString::Rep::empty();
       
   180     UCharBuffer buf = {s, length}; 
       
   181     pair<HashSet<UString::Rep*>::iterator, bool> addResult = globalData->identifierTable->add<UCharBuffer, IdentifierUCharBufferTranslator>(buf);
       
   182 
       
   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;
       
   186 }
       
   187 
       
   188 PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length)
       
   189 {
       
   190     return add(&exec->globalData(), s, length);
       
   191 }
       
   192 
       
   193 PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r)
       
   194 {
       
   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.
       
   198     ASSERT(r->length());
       
   199 
       
   200     if (r->length() == 1) {
       
   201         UChar c = r->characters()[0];
       
   202         if (c <= 0xFF)
       
   203             r = globalData->smallStrings.singleCharacterStringRep(c);
       
   204             if (r->isIdentifier())
       
   205                 return r;
       
   206     }
       
   207 
       
   208     return *globalData->identifierTable->add(r).first;
       
   209 }
       
   210 
       
   211 PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r)
       
   212 {
       
   213     return addSlowCase(&exec->globalData(), r);
       
   214 }
       
   215 
       
   216 Identifier Identifier::from(ExecState* exec, unsigned value)
       
   217 {
       
   218     return Identifier(exec, exec->globalData().numericStrings.add(value));
       
   219 }
       
   220 
       
   221 Identifier Identifier::from(ExecState* exec, int value)
       
   222 {
       
   223     return Identifier(exec, exec->globalData().numericStrings.add(value));
       
   224 }
       
   225 
       
   226 Identifier Identifier::from(ExecState* exec, double value)
       
   227 {
       
   228     return Identifier(exec, exec->globalData().numericStrings.add(value));
       
   229 }
       
   230 
       
   231 Identifier Identifier::from(JSGlobalData* globalData, unsigned value)
       
   232 {
       
   233     return Identifier(globalData, globalData->numericStrings.add(value));
       
   234 }
       
   235 
       
   236 Identifier Identifier::from(JSGlobalData* globalData, int value)
       
   237 {
       
   238     return Identifier(globalData, globalData->numericStrings.add(value));
       
   239 }
       
   240 
       
   241 Identifier Identifier::from(JSGlobalData* globalData, double value)
       
   242 {
       
   243     return Identifier(globalData, globalData->numericStrings.add(value));
       
   244 }
       
   245 
       
   246 #ifndef NDEBUG
       
   247 
       
   248 void Identifier::checkCurrentIdentifierTable(JSGlobalData* globalData)
       
   249 {
       
   250     // Check the identifier table accessible through the threadspecific matches the
       
   251     // globalData's identifier table.
       
   252     ASSERT_UNUSED(globalData, globalData->identifierTable == wtfThreadData().currentIdentifierTable());
       
   253 }
       
   254 
       
   255 void Identifier::checkCurrentIdentifierTable(ExecState* exec)
       
   256 {
       
   257     checkCurrentIdentifierTable(&exec->globalData());
       
   258 }
       
   259 
       
   260 #else
       
   261 
       
   262 // These only exists so that our exports are the same for debug and release builds.
       
   263 // This would be an ASSERT_NOT_REACHED(), but we're in NDEBUG only code here!
       
   264 void Identifier::checkCurrentIdentifierTable(JSGlobalData*) { CRASH(); }
       
   265 void Identifier::checkCurrentIdentifierTable(ExecState*) { CRASH(); }
       
   266 
       
   267 #endif
       
   268 
       
   269 } // namespace JSC