Changeset 49798 in webkit


Ignore:
Timestamp:
Oct 19, 2009 12:11:37 PM (15 years ago)
Author:
eric@webkit.org
Message:

2009-10-19 Jens Alfke <jens@mooseyard.com>

Reviewed by Darin Adler.

Optimize string upper/lowercasing
https://bugs.webkit.org/show_bug.cgi?id=30261

  • Added AtomicString::upper() and lower()
  • Further optimized StringImpl::lower()
  • Removed StringImpl::isLower()
  • Added QualifiedName::localNameUpper(), which is cached, thereby saving thousands of upper() calls and string allocations.
  • dom/Element.cpp: (WebCore::Element::setAttribute): Call AtomicString::lower()
  • dom/QualifiedName.cpp: (WebCore::QualifiedName::localNameUpper): New method
  • dom/QualifiedName.h: Added localNameUpper() method
  • dom/StyledElement.cpp: (WebCore::StyledElement::parseMappedAttribute): Call AtomicString::lower()
  • html/HTMLDocument.cpp: (WebCore::HTMLDocument::createElement): Call AtomicString::lower()
  • html/HTMLElement.cpp: (WebCore::HTMLElement::nodeName): Call localNameUpper()
  • platform/text/AtomicString.cpp: (WebCore::AtomicString::lower): New method (WebCore::AtomicString::upper): New method
  • platform/text/AtomicString.h: Added lower() and upper()
  • platform/text/StringImpl.cpp: Removed isLower() (WebCore::StringImpl::lower): Further optimization of initial loop
  • platform/text/StringImpl.h: Removed isLower()
Location:
trunk/WebCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r49796 r49798  
     12009-10-19  Jens Alfke  <jens@mooseyard.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        Optimize string upper/lowercasing
     6        https://bugs.webkit.org/show_bug.cgi?id=30261
     7       
     8        - Added AtomicString::upper() and lower()
     9        - Further optimized StringImpl::lower()
     10        - Removed StringImpl::isLower()
     11        - Added QualifiedName::localNameUpper(), which is cached, thereby saving
     12          thousands of upper() calls and string allocations.
     13 
     14         * dom/Element.cpp:
     15         (WebCore::Element::setAttribute): Call AtomicString::lower()
     16         * dom/QualifiedName.cpp:
     17         (WebCore::QualifiedName::localNameUpper): New method
     18         * dom/QualifiedName.h: Added localNameUpper() method
     19         * dom/StyledElement.cpp:
     20         (WebCore::StyledElement::parseMappedAttribute):  Call AtomicString::lower()
     21         * html/HTMLDocument.cpp:
     22         (WebCore::HTMLDocument::createElement): Call AtomicString::lower()
     23         * html/HTMLElement.cpp:
     24         (WebCore::HTMLElement::nodeName): Call localNameUpper()
     25         * platform/text/AtomicString.cpp:
     26         (WebCore::AtomicString::lower): New method
     27         (WebCore::AtomicString::upper): New method
     28         * platform/text/AtomicString.h: Added lower() and upper()
     29         * platform/text/StringImpl.cpp: Removed isLower()
     30         (WebCore::StringImpl::lower): Further optimization of initial loop
     31         * platform/text/StringImpl.h: Removed isLower()
     32 
    1332009-10-19  Nate Chapin  <japhet@chromium.org>
    234
  • trunk/WebCore/dom/Element.cpp

    r49792 r49798  
    517517    }
    518518
    519     const AtomicString& localName = (shouldIgnoreAttributeCase(this) && !name.string().impl()->isLower()) ? AtomicString(name.string().lower()) : name;
     519    const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
    520520
    521521    // allocate attributemap if necessary
  • trunk/WebCore/dom/QualifiedName.cpp

    r44147 r49798  
    9898}
    9999
     100const AtomicString& QualifiedName::localNameUpper() const
     101{
     102    if (!m_impl->m_localNameUpper)
     103        m_impl->m_localNameUpper = m_impl->m_localName.upper();
     104    return m_impl->m_localNameUpper;
    100105}
     106
     107}
  • trunk/WebCore/dom/QualifiedName.h

    r44147 r49798  
    4242        }
    4343
    44         AtomicString m_prefix;
    45         AtomicString m_localName;
    46         AtomicString m_namespace;
     44        const AtomicString m_prefix;
     45        const AtomicString m_localName;
     46        const AtomicString m_namespace;
     47        mutable AtomicString m_localNameUpper;
    4748
    4849    private:
     
    7677    const AtomicString& localName() const { return m_impl->m_localName; }
    7778    const AtomicString& namespaceURI() const { return m_impl->m_namespace; }
     79
     80    // Uppercased localName, cached for efficiency
     81    const AtomicString& localNameUpper() const;
    7882
    7983    String toString() const;
  • trunk/WebCore/dom/StyledElement.cpp

    r47688 r49798  
    241241            if (attr->isNull())
    242242                namedAttrMap->setID(nullAtom);
    243             else if (document()->inCompatMode() && !attr->value().impl()->isLower())
    244                 namedAttrMap->setID(AtomicString(attr->value().string().lower()));
     243            else if (document()->inCompatMode())
     244                namedAttrMap->setID(attr->value().lower());
    245245            else
    246246                namedAttrMap->setID(attr->value());
  • trunk/WebCore/html/HTMLDocument.cpp

    r48430 r49798  
    308308        return 0;
    309309    }
    310     AtomicString lowerName = name.string().impl()->isLower() ? name : AtomicString(name.string().lower());
    311     return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, lowerName, xhtmlNamespaceURI), this, 0, false);
     310    return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name.lower(), xhtmlNamespaceURI), this, 0, false);
    312311}
    313312
  • trunk/WebCore/html/HTMLElement.cpp

    r48106 r49798  
    6868    // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it.
    6969    if (document()->isHTMLDocument() && !tagQName().hasPrefix())
    70         return tagQName().localName().string().upper();
     70        return tagQName().localNameUpper();
    7171    return Element::nodeName();
    7272}
  • trunk/WebCore/platform/text/AtomicString.cpp

    r49322 r49798  
    229229    stringTable().remove(r);
    230230}
     231   
     232AtomicString AtomicString::lower() const
     233{
     234    // Note: This is a hot function in the Dromaeo benchmark.
     235    StringImpl* impl = this->impl();
     236    RefPtr<StringImpl> newImpl = impl->lower();
     237    if (LIKELY(newImpl == impl))
     238        return *this;
     239    return AtomicString(newImpl);
     240}
    231241
    232242#if USE(JSC)
  • trunk/WebCore/platform/text/AtomicString.h

    r42245 r49798  
    8484        { return m_string.endsWith(s, caseSensitive); }
    8585   
     86    AtomicString lower() const;
     87    AtomicString upper() const { return AtomicString(impl()->upper()); }
     88   
    8689    int toInt(bool* ok = 0) const { return m_string.toInt(ok); }
    8790    double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); }
  • trunk/WebCore/platform/text/StringImpl.cpp

    r49403 r49798  
    150150}
    151151
    152 bool StringImpl::isLower()
    153 {
    154     // Do a faster loop for the case where all the characters are ASCII.
    155     bool allLower = true;
    156     UChar ored = 0;
    157     for (unsigned i = 0; i < m_length; i++) {
    158         UChar c = m_data[i];
    159         allLower = allLower && isASCIILower(c);
    160         ored |= c;
    161     }
    162     if (!(ored & ~0x7F))
    163         return allLower;
    164 
    165     // Do a slower check for cases that include non-ASCII characters.
    166     allLower = true;
    167     unsigned i = 0;
    168     while (i < m_length) {
    169         UChar32 character;
    170         U16_NEXT(m_data, i, m_length, character)
    171         allLower = allLower && Unicode::isLower(character);
    172     }
    173     return allLower;
    174 }
    175 
    176152PassRefPtr<StringImpl> StringImpl::lower()
    177153{
     154    // Note: This is a hot function in the Dromaeo benchmark, specifically the
     155    // no-op code path up through the first 'return' statement.
     156   
    178157    // First scan the string for uppercase and non-ASCII characters:
    179     int32_t length = m_length;
    180158    UChar ored = 0;
    181159    bool noUpper = true;
    182     for (int i = 0; i < length; i++) {
    183         UChar c = m_data[i];
    184         ored |= c;
    185         noUpper = noUpper && !isASCIIUpper(c);
     160    const UChar *end = m_data + m_length;
     161    for (const UChar* chp = m_data; chp != end; chp++) {
     162        if (UNLIKELY(isASCIIUpper(*chp)))
     163            noUpper = false;
     164        ored |= *chp;
    186165    }
    187166   
     
    190169        return this;
    191170
     171    int32_t length = m_length;
    192172    UChar* data;
    193173    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
  • trunk/WebCore/platform/text/StringImpl.h

    r49322 r49798  
    136136    float toFloat(bool* ok = 0);
    137137
    138     bool isLower();
    139138    PassRefPtr<StringImpl> lower();
    140139    PassRefPtr<StringImpl> upper();
Note: See TracChangeset for help on using the changeset viewer.