From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WTF/wtf/text/AtomicString.cpp | 467 ++++------------------------------- 1 file changed, 48 insertions(+), 419 deletions(-) (limited to 'Source/WTF/wtf/text/AtomicString.cpp') diff --git a/Source/WTF/wtf/text/AtomicString.cpp b/Source/WTF/wtf/text/AtomicString.cpp index 5803dd018..cd8ef8ffc 100644 --- a/Source/WTF/wtf/text/AtomicString.cpp +++ b/Source/WTF/wtf/text/AtomicString.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2004-2008, 2013-2014, 2016 Apple Inc. All rights reserved. * Copyright (C) 2010 Patrick Gansterer * Copyright (C) 2012 Google Inc. All rights reserved. * @@ -23,452 +23,81 @@ #include "config.h" #include "AtomicString.h" -#include "AtomicStringTable.h" -#include "HashSet.h" #include "IntegerToStringConversion.h" -#include "StringHash.h" -#include "Threading.h" -#include "WTFThreadData.h" #include "dtoa.h" -#include #if USE(WEB_THREAD) -#include "TCSpinLock.h" +#include "Lock.h" #endif namespace WTF { -using namespace Unicode; - -static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must be same size!"); - -#if USE(WEB_THREAD) - -class AtomicStringTableLocker : public SpinLockHolder { - WTF_MAKE_NONCOPYABLE(AtomicStringTableLocker); - - static SpinLock s_stringTableLock; -public: - AtomicStringTableLocker() - : SpinLockHolder(&s_stringTableLock) - { - } -}; - -SpinLock AtomicStringTableLocker::s_stringTableLock = SPINLOCK_INITIALIZER; - -#else - -class AtomicStringTableLocker { - WTF_MAKE_NONCOPYABLE(AtomicStringTableLocker); -public: - AtomicStringTableLocker() { } -}; - -#endif // USE(WEB_THREAD) - -static ALWAYS_INLINE HashSet& stringTable() -{ - return wtfThreadData().atomicStringTable()->table(); -} - -template -static inline PassRefPtr addToStringTable(const T& value) -{ - AtomicStringTableLocker locker; - - HashSet::AddResult addResult = stringTable().add(value); - - // If the string is newly-translated, then we need to adopt it. - // The boolean in the pair tells us if that is so. - return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator; -} - -struct CStringTranslator { - static unsigned hash(const LChar* c) - { - return StringHasher::computeHashAndMaskTop8Bits(c); - } - - static inline bool equal(StringImpl* r, const LChar* s) - { - return WTF::equal(r, s); - } - - static void translate(StringImpl*& location, const LChar* const& c, unsigned hash) - { - location = &StringImpl::create(c).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -PassRefPtr AtomicString::add(const LChar* c) +template +ALWAYS_INLINE AtomicString AtomicString::convertASCIICase() const { - if (!c) - return 0; - if (!*c) - return StringImpl::empty(); - - return addToStringTable(c); -} - -template -struct HashTranslatorCharBuffer { - const CharacterType* s; - unsigned length; -}; - -typedef HashTranslatorCharBuffer UCharBuffer; -struct UCharBufferTranslator { - static unsigned hash(const UCharBuffer& buf) - { - return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); - } - - static bool equal(StringImpl* const& str, const UCharBuffer& buf) - { - return WTF::equal(str, buf.s, buf.length); - } - - static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash) - { - location = &StringImpl::create8BitIfPossible(buf.s, buf.length).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -template -struct HashAndCharacters { - unsigned hash; - const CharacterType* characters; - unsigned length; -}; - -template -struct HashAndCharactersTranslator { - static unsigned hash(const HashAndCharacters& buffer) - { - ASSERT(buffer.hash == StringHasher::computeHashAndMaskTop8Bits(buffer.characters, buffer.length)); - return buffer.hash; - } - - static bool equal(StringImpl* const& string, const HashAndCharacters& buffer) - { - return WTF::equal(string, buffer.characters, buffer.length); - } - - static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash) - { - location = &StringImpl::create(buffer.characters, buffer.length).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; + StringImpl* impl = this->impl(); + if (UNLIKELY(!impl)) + return nullAtom; -struct HashAndUTF8Characters { - unsigned hash; - const char* characters; + // Convert short strings without allocating a new StringImpl, since + // there's a good chance these strings are already in the atomic + // string table and so no memory allocation will be required. unsigned length; - unsigned utf16Length; -}; - -struct HashAndUTF8CharactersTranslator { - static unsigned hash(const HashAndUTF8Characters& buffer) - { - return buffer.hash; - } - - static bool equal(StringImpl* const& string, const HashAndUTF8Characters& buffer) - { - if (buffer.utf16Length != string->length()) - return false; - - // If buffer contains only ASCII characters UTF-8 and UTF16 length are the same. - if (buffer.utf16Length != buffer.length) { - const UChar* stringCharacters = string->deprecatedCharacters(); - - return equalUTF16WithUTF8(stringCharacters, stringCharacters + string->length(), buffer.characters, buffer.characters + buffer.length); - } - - if (string->is8Bit()) { - const LChar* stringCharacters = string->characters8(); - - for (unsigned i = 0; i < buffer.length; ++i) { - ASSERT(isASCII(buffer.characters[i])); - if (stringCharacters[i] != buffer.characters[i]) - return false; + const unsigned localBufferSize = 100; + if (impl->is8Bit() && (length = impl->length()) <= localBufferSize) { + const LChar* characters = impl->characters8(); + unsigned failingIndex; + for (unsigned i = 0; i < length; ++i) { + if (type == CaseConvertType::Lower ? UNLIKELY(isASCIIUpper(characters[i])) : LIKELY(isASCIILower(characters[i]))) { + failingIndex = i; + goto SlowPath; } - - return true; } - - const UChar* stringCharacters = string->characters16(); - - for (unsigned i = 0; i < buffer.length; ++i) { - ASSERT(isASCII(buffer.characters[i])); - if (stringCharacters[i] != buffer.characters[i]) - return false; - } - - return true; - } - - static void translate(StringImpl*& location, const HashAndUTF8Characters& buffer, unsigned hash) - { - UChar* target; - RefPtr newString = StringImpl::createUninitialized(buffer.utf16Length, target); - - bool isAllASCII; - const char* source = buffer.characters; - if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target + buffer.utf16Length, &isAllASCII) != conversionOK) - ASSERT_NOT_REACHED(); - - if (isAllASCII) - newString = StringImpl::create(buffer.characters, buffer.length); - - location = newString.release().leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -PassRefPtr AtomicString::add(const UChar* s, unsigned length) -{ - if (!s) - return 0; - - if (!length) - return StringImpl::empty(); - - UCharBuffer buffer = { s, length }; - return addToStringTable(buffer); -} - -PassRefPtr AtomicString::add(const UChar* s, unsigned length, unsigned existingHash) -{ - ASSERT(s); - ASSERT(existingHash); - - if (!length) - return StringImpl::empty(); - - HashAndCharacters buffer = { existingHash, s, length }; - return addToStringTable, HashAndCharactersTranslator>(buffer); -} - -PassRefPtr AtomicString::add(const UChar* s) -{ - if (!s) - return 0; - - unsigned length = 0; - while (s[length] != UChar(0)) - ++length; - - if (!length) - return StringImpl::empty(); - - UCharBuffer buffer = { s, length }; - return addToStringTable(buffer); -} - -struct SubstringLocation { - StringImpl* baseString; - unsigned start; - unsigned length; -}; - -struct SubstringTranslator { - static unsigned hash(const SubstringLocation& buffer) - { - return StringHasher::computeHashAndMaskTop8Bits(buffer.baseString->deprecatedCharacters() + buffer.start, buffer.length); - } - - static bool equal(StringImpl* const& string, const SubstringLocation& buffer) - { - return WTF::equal(string, buffer.baseString->deprecatedCharacters() + buffer.start, buffer.length); + return *this; +SlowPath: + LChar localBuffer[localBufferSize]; + for (unsigned i = 0; i < failingIndex; ++i) + localBuffer[i] = characters[i]; + for (unsigned i = failingIndex; i < length; ++i) + localBuffer[i] = type == CaseConvertType::Lower ? toASCIILower(characters[i]) : toASCIIUpper(characters[i]); + return AtomicString(localBuffer, length); } - static void translate(StringImpl*& location, const SubstringLocation& buffer, unsigned hash) - { - location = &StringImpl::create(buffer.baseString, buffer.start, buffer.length).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -PassRefPtr AtomicString::add(StringImpl* baseString, unsigned start, unsigned length) -{ - if (!baseString) - return 0; - - if (!length || start >= baseString->length()) - return StringImpl::empty(); + Ref convertedString = type == CaseConvertType::Lower ? impl->convertToASCIILowercase() : impl->convertToASCIIUppercase(); + if (LIKELY(convertedString.ptr() == impl)) + return *this; - unsigned maxLength = baseString->length() - start; - if (length >= maxLength) { - if (!start) - return add(baseString); - length = maxLength; - } - - SubstringLocation buffer = { baseString, start, length }; - return addToStringTable(buffer); + AtomicString result; + result.m_string = AtomicStringImpl::add(convertedString.ptr()); + return result; } - -typedef HashTranslatorCharBuffer LCharBuffer; -struct LCharBufferTranslator { - static unsigned hash(const LCharBuffer& buf) - { - return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); - } - - static bool equal(StringImpl* const& str, const LCharBuffer& buf) - { - return WTF::equal(str, buf.s, buf.length); - } - - static void translate(StringImpl*& location, const LCharBuffer& buf, unsigned hash) - { - location = &StringImpl::create(buf.s, buf.length).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -typedef HashTranslatorCharBuffer CharBuffer; -struct CharBufferFromLiteralDataTranslator { - static unsigned hash(const CharBuffer& buf) - { - return StringHasher::computeHashAndMaskTop8Bits(reinterpret_cast(buf.s), buf.length); - } - static bool equal(StringImpl* const& str, const CharBuffer& buf) - { - return WTF::equal(str, buf.s, buf.length); - } - - static void translate(StringImpl*& location, const CharBuffer& buf, unsigned hash) - { - location = &StringImpl::createFromLiteral(buf.s, buf.length).leakRef(); - location->setHash(hash); - location->setIsAtomic(true); - } -}; - -PassRefPtr AtomicString::add(const LChar* s, unsigned length) +AtomicString AtomicString::convertToASCIILowercase() const { - if (!s) - return 0; - - if (!length) - return StringImpl::empty(); - - LCharBuffer buffer = { s, length }; - return addToStringTable(buffer); + return convertASCIICase(); } -PassRefPtr AtomicString::addFromLiteralData(const char* characters, unsigned length) +AtomicString AtomicString::convertToASCIIUppercase() const { - ASSERT(characters); - ASSERT(length); - - CharBuffer buffer = { characters, length }; - return addToStringTable(buffer); + return convertASCIICase(); } -PassRefPtr AtomicString::addSlowCase(StringImpl* string) -{ - if (!string->length()) - return StringImpl::empty(); - - ASSERT_WITH_MESSAGE(!string->isAtomic(), "AtomicString should not hit the slow case if the string is already atomic."); - - AtomicStringTableLocker locker; - HashSet::AddResult addResult = stringTable().add(string); - - if (addResult.isNewEntry) { - ASSERT(*addResult.iterator == string); - string->setIsAtomic(true); - } - - return *addResult.iterator; -} - -template -static inline HashSet::iterator findString(const StringImpl* stringImpl) -{ - HashAndCharacters buffer = { stringImpl->existingHash(), stringImpl->getCharacters(), stringImpl->length() }; - return stringTable().find>(buffer); -} - -AtomicStringImpl* AtomicString::find(const StringImpl* stringImpl) -{ - ASSERT(stringImpl); - ASSERT(stringImpl->existingHash()); - - if (!stringImpl->length()) - return static_cast(StringImpl::empty()); - - AtomicStringTableLocker locker; - HashSet::iterator iterator; - if (stringImpl->is8Bit()) - iterator = findString(stringImpl); - else - iterator = findString(stringImpl); - if (iterator == stringTable().end()) - return 0; - return static_cast(*iterator); -} - -void AtomicString::remove(StringImpl* string) -{ - ASSERT(string->isAtomic()); - AtomicStringTableLocker locker; - HashSet& atomicStringTable = stringTable(); - HashSet::iterator iterator = atomicStringTable.find(string); - ASSERT_WITH_MESSAGE(iterator != atomicStringTable.end(), "The string being removed is atomic in the string table of an other thread!"); - atomicStringTable.remove(iterator); -} - -AtomicString AtomicString::lower() const +AtomicString AtomicString::number(int number) { - // Note: This is a hot function in the Dromaeo benchmark. - StringImpl* impl = this->impl(); - if (UNLIKELY(!impl)) - return AtomicString(); - - RefPtr lowerImpl = impl->lower(); - AtomicString returnValue; - if (LIKELY(lowerImpl == impl)) - returnValue.m_string = lowerImpl.release(); - else - returnValue.m_string = addSlowCase(lowerImpl.get()); - return returnValue; + return numberToStringSigned(number); } -AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd) +AtomicString AtomicString::number(unsigned number) { - HashAndUTF8Characters buffer; - buffer.characters = charactersStart; - buffer.hash = calculateStringHashAndLengthFromUTF8MaskingTop8Bits(charactersStart, charactersEnd, buffer.length, buffer.utf16Length); - - if (!buffer.hash) - return nullAtom; - - AtomicString atomicString; - atomicString.m_string = addToStringTable(buffer); - return atomicString; + return numberToStringUnsigned(number); } -AtomicString AtomicString::number(int number) +AtomicString AtomicString::number(unsigned long number) { - return numberToStringSigned(number); + return numberToStringUnsigned(number); } -AtomicString AtomicString::number(unsigned number) +AtomicString AtomicString::number(unsigned long long number) { return numberToStringUnsigned(number); } @@ -479,13 +108,13 @@ AtomicString AtomicString::number(double number) return String(numberToFixedPrecisionString(number, 6, buffer, true)); } -#if !ASSERT_DISABLED -bool AtomicString::isInAtomicStringTable(StringImpl* string) +AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const char* charactersEnd) { - AtomicStringTableLocker locker; - return stringTable().contains(string); + auto impl = AtomicStringImpl::addUTF8(charactersStart, charactersEnd); + if (!impl) + return nullAtom; + return impl.get(); } -#endif #ifndef NDEBUG void AtomicString::show() const -- cgit v1.2.1