Investigate storing strings in 8-bit buffers when possible
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Oct 2011 20:16:20 +0000 (20:16 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 27 Oct 2011 20:16:20 +0000 (20:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=66161

Source/JavaScriptCore:

Investigate storing strings in 8-bit buffers when possible
https://bugs.webkit.org/show_bug.cgi?id=66161

Added support for 8 bit string data in StringImpl.  Changed
(UChar*) m_data to m_data16.  Added char* m_data8 as a union
with m_data16.  Added UChar* m_copyData16 to the other union
to store a 16 bit copy of an 8 bit string when needed.
Added characters8() and characters16() accessor methods
that assume the caller has checked the underlying string type
via the new is8Bit() method. The characters() method will
return a UChar* of the string, materializing a 16 bit copy if the
string is an 8 bit string.  Added two flags, one for 8 bit buffer
and a second for a 16 bit copy for an 8 bit string.

Fixed method name typo (StringHasher::defaultCoverter()).

Over time the goal is to eliminate calls to characters() and
us the character8() and characters16() accessors.

This patch does not include changes that actually create 8 bit
strings. This is the first of at least 8 patches.  Subsequent
patches will be submitted for JIT changes, making the JSC lexer,
parser and literal parser, JavaScript string changes and
then changes in webcore to take advantage of the 8 bit strings.

This change is performance neutral for SunSpider and V8 when
run from the command line with "jsc".

Reviewed by Geoffrey Garen.

* JavaScriptCore.exp:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
* interpreter/Interpreter.cpp:
(JSC::Interpreter::callEval):
* parser/SourceProvider.h:
(JSC::UStringSourceProvider::data):
(JSC::UStringSourceProvider::UStringSourceProvider):
* runtime/Identifier.cpp:
(JSC::IdentifierCStringTranslator::hash):
(JSC::IdentifierCStringTranslator::equal):
(JSC::IdentifierCStringTranslator::translate):
(JSC::Identifier::add):
(JSC::Identifier::toUInt32):
* runtime/Identifier.h:
(JSC::Identifier::equal):
(JSC::operator==):
(JSC::operator!=):
* runtime/JSString.cpp:
(JSC::JSString::resolveRope):
(JSC::JSString::resolveRopeSlowCase):
* runtime/RegExp.cpp:
(JSC::RegExp::match):
* runtime/StringPrototype.cpp:
(JSC::jsSpliceSubstringsWithSeparators):
* runtime/UString.cpp:
(JSC::UString::UString):
(JSC::equalSlowCase):
(JSC::UString::utf8):
* runtime/UString.h:
(JSC::UString::characters):
(JSC::UString::characters8):
(JSC::UString::characters16):
(JSC::UString::is8Bit):
(JSC::UString::operator[]):
(JSC::UString::find):
(JSC::operator==):
* wtf/StringHasher.h:
(WTF::StringHasher::computeHash):
(WTF::StringHasher::defaultConverter):
* wtf/text/AtomicString.cpp:
(WTF::CStringTranslator::hash):
(WTF::CStringTranslator::equal):
(WTF::CStringTranslator::translate):
(WTF::AtomicString::add):
* wtf/text/AtomicString.h:
(WTF::AtomicString::AtomicString):
(WTF::AtomicString::contains):
(WTF::AtomicString::find):
(WTF::AtomicString::add):
(WTF::operator==):
(WTF::operator!=):
(WTF::equalIgnoringCase):
* wtf/text/StringConcatenate.h:
* wtf/text/StringHash.h:
(WTF::StringHash::equal):
(WTF::CaseFoldingHash::hash):
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::~StringImpl):
(WTF::StringImpl::createUninitialized):
(WTF::StringImpl::create):
(WTF::StringImpl::getData16SlowCase):
(WTF::StringImpl::containsOnlyWhitespace):
(WTF::StringImpl::substring):
(WTF::StringImpl::characterStartingAt):
(WTF::StringImpl::lower):
(WTF::StringImpl::upper):
(WTF::StringImpl::fill):
(WTF::StringImpl::foldCase):
(WTF::StringImpl::stripMatchedCharacters):
(WTF::StringImpl::removeCharacters):
(WTF::StringImpl::simplifyMatchedCharactersToSpace):
(WTF::StringImpl::toIntStrict):
(WTF::StringImpl::toUIntStrict):
(WTF::StringImpl::toInt64Strict):
(WTF::StringImpl::toUInt64Strict):
(WTF::StringImpl::toIntPtrStrict):
(WTF::StringImpl::toInt):
(WTF::StringImpl::toUInt):
(WTF::StringImpl::toInt64):
(WTF::StringImpl::toUInt64):
(WTF::StringImpl::toIntPtr):
(WTF::StringImpl::toDouble):
(WTF::StringImpl::toFloat):
(WTF::equal):
(WTF::equalIgnoringCase):
(WTF::StringImpl::find):
(WTF::StringImpl::findIgnoringCase):
(WTF::StringImpl::reverseFind):
(WTF::StringImpl::replace):
(WTF::StringImpl::defaultWritingDirection):
(WTF::StringImpl::adopt):
(WTF::StringImpl::createWithTerminatingNullCharacter):
* wtf/text/StringImpl.h:
(WTF::StringImpl::StringImpl):
(WTF::StringImpl::create):
(WTF::StringImpl::create8):
(WTF::StringImpl::tryCreateUninitialized):
(WTF::StringImpl::flagsOffset):
(WTF::StringImpl::flagIs8Bit):
(WTF::StringImpl::dataOffset):
(WTF::StringImpl::is8Bit):
(WTF::StringImpl::characters8):
(WTF::StringImpl::characters16):
(WTF::StringImpl::characters):
(WTF::StringImpl::has16BitShadow):
(WTF::StringImpl::setHash):
(WTF::StringImpl::hash):
(WTF::StringImpl::copyChars):
(WTF::StringImpl::operator[]):
(WTF::StringImpl::find):
(WTF::StringImpl::findIgnoringCase):
(WTF::equal):
(WTF::equalIgnoringCase):
(WTF::StringImpl::isolatedCopy):
* wtf/text/WTFString.cpp:
(WTF::String::String):
(WTF::String::append):
(WTF::String::format):
(WTF::String::fromUTF8):
(WTF::String::fromUTF8WithLatin1Fallback):
* wtf/text/WTFString.h:
(WTF::String::find):
(WTF::String::findIgnoringCase):
(WTF::String::contains):
(WTF::String::append):
(WTF::String::fromUTF8):
(WTF::String::fromUTF8WithLatin1Fallback):
(WTF::operator==):
(WTF::operator!=):
(WTF::equalIgnoringCase):
* wtf/unicode/Unicode.h:
* yarr/YarrJIT.cpp:
(JSC::Yarr::execute):
* yarr/YarrJIT.h:
(JSC::Yarr::YarrCodeBlock::execute):
* yarr/YarrParser.h:
(JSC::Yarr::Parser::Parser):

Source/WebCore:

Changes to support 8 bit StringImpl changes.

Reviewed by Geoffrey Garen.

No new tests, refactored StringImpl for 8 bit strings.

* platform/text/cf/StringImplCF.cpp:
(WTF::StringImpl::createCFString):

Source/WebKit2:

Added export of StringImpl::getData16SlowCase for linking tests.

Reviewed by Geoffrey Garen.

* win/WebKit2.def:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@98624 268f45cc-cd09-0410-ab3c-d52691b4dbfc

29 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.exp
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/parser/SourceProvider.h
Source/JavaScriptCore/runtime/Identifier.cpp
Source/JavaScriptCore/runtime/Identifier.h
Source/JavaScriptCore/runtime/JSString.cpp
Source/JavaScriptCore/runtime/RegExp.cpp
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/UString.cpp
Source/JavaScriptCore/runtime/UString.h
Source/JavaScriptCore/wtf/StringHasher.h
Source/JavaScriptCore/wtf/text/AtomicString.cpp
Source/JavaScriptCore/wtf/text/AtomicString.h
Source/JavaScriptCore/wtf/text/StringConcatenate.h
Source/JavaScriptCore/wtf/text/StringHash.h
Source/JavaScriptCore/wtf/text/StringImpl.cpp
Source/JavaScriptCore/wtf/text/StringImpl.h
Source/JavaScriptCore/wtf/text/WTFString.cpp
Source/JavaScriptCore/wtf/text/WTFString.h
Source/JavaScriptCore/wtf/unicode/Unicode.h
Source/JavaScriptCore/yarr/YarrJIT.cpp
Source/JavaScriptCore/yarr/YarrJIT.h
Source/JavaScriptCore/yarr/YarrParser.h
Source/WebCore/ChangeLog
Source/WebCore/platform/text/cf/StringImplCF.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/win/WebKit2.def

index 289edba..d7347af 100644 (file)
@@ -1,3 +1,176 @@
+2011-10-27  Michael Saboff  <msaboff@apple.com>
+
+        Investigate storing strings in 8-bit buffers when possible
+        https://bugs.webkit.org/show_bug.cgi?id=66161
+
+        Investigate storing strings in 8-bit buffers when possible
+        https://bugs.webkit.org/show_bug.cgi?id=66161
+
+        Added support for 8 bit string data in StringImpl.  Changed
+        (UChar*) m_data to m_data16.  Added char* m_data8 as a union
+        with m_data16.  Added UChar* m_copyData16 to the other union
+        to store a 16 bit copy of an 8 bit string when needed.
+        Added characters8() and characters16() accessor methods
+        that assume the caller has checked the underlying string type
+        via the new is8Bit() method. The characters() method will
+        return a UChar* of the string, materializing a 16 bit copy if the
+        string is an 8 bit string.  Added two flags, one for 8 bit buffer
+        and a second for a 16 bit copy for an 8 bit string.
+
+        Fixed method name typo (StringHasher::defaultCoverter()).
+
+        Over time the goal is to eliminate calls to characters() and
+        us the character8() and characters16() accessors.
+
+        This patch does not include changes that actually create 8 bit
+        strings. This is the first of at least 8 patches.  Subsequent
+        patches will be submitted for JIT changes, making the JSC lexer,
+        parser and literal parser, JavaScript string changes and
+        then changes in webcore to take advantage of the 8 bit strings.
+
+        This change is performance neutral for SunSpider and V8 when
+        run from the command line with "jsc".
+
+        Reviewed by Geoffrey Garen.
+
+        * JavaScriptCore.exp:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::callEval):
+        * parser/SourceProvider.h:
+        (JSC::UStringSourceProvider::data):
+        (JSC::UStringSourceProvider::UStringSourceProvider):
+        * runtime/Identifier.cpp:
+        (JSC::IdentifierCStringTranslator::hash):
+        (JSC::IdentifierCStringTranslator::equal):
+        (JSC::IdentifierCStringTranslator::translate):
+        (JSC::Identifier::add):
+        (JSC::Identifier::toUInt32):
+        * runtime/Identifier.h:
+        (JSC::Identifier::equal):
+        (JSC::operator==):
+        (JSC::operator!=):
+        * runtime/JSString.cpp:
+        (JSC::JSString::resolveRope):
+        (JSC::JSString::resolveRopeSlowCase):
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::match):
+        * runtime/StringPrototype.cpp:
+        (JSC::jsSpliceSubstringsWithSeparators):
+        * runtime/UString.cpp:
+        (JSC::UString::UString):
+        (JSC::equalSlowCase):
+        (JSC::UString::utf8):
+        * runtime/UString.h:
+        (JSC::UString::characters):
+        (JSC::UString::characters8):
+        (JSC::UString::characters16):
+        (JSC::UString::is8Bit):
+        (JSC::UString::operator[]):
+        (JSC::UString::find):
+        (JSC::operator==):
+        * wtf/StringHasher.h:
+        (WTF::StringHasher::computeHash):
+        (WTF::StringHasher::defaultConverter):
+        * wtf/text/AtomicString.cpp:
+        (WTF::CStringTranslator::hash):
+        (WTF::CStringTranslator::equal):
+        (WTF::CStringTranslator::translate):
+        (WTF::AtomicString::add):
+        * wtf/text/AtomicString.h:
+        (WTF::AtomicString::AtomicString):
+        (WTF::AtomicString::contains):
+        (WTF::AtomicString::find):
+        (WTF::AtomicString::add):
+        (WTF::operator==):
+        (WTF::operator!=):
+        (WTF::equalIgnoringCase):
+        * wtf/text/StringConcatenate.h:
+        * wtf/text/StringHash.h:
+        (WTF::StringHash::equal):
+        (WTF::CaseFoldingHash::hash):
+        * wtf/text/StringImpl.cpp:
+        (WTF::StringImpl::~StringImpl):
+        (WTF::StringImpl::createUninitialized):
+        (WTF::StringImpl::create):
+        (WTF::StringImpl::getData16SlowCase):
+        (WTF::StringImpl::containsOnlyWhitespace):
+        (WTF::StringImpl::substring):
+        (WTF::StringImpl::characterStartingAt):
+        (WTF::StringImpl::lower):
+        (WTF::StringImpl::upper):
+        (WTF::StringImpl::fill):
+        (WTF::StringImpl::foldCase):
+        (WTF::StringImpl::stripMatchedCharacters):
+        (WTF::StringImpl::removeCharacters):
+        (WTF::StringImpl::simplifyMatchedCharactersToSpace):
+        (WTF::StringImpl::toIntStrict):
+        (WTF::StringImpl::toUIntStrict):
+        (WTF::StringImpl::toInt64Strict):
+        (WTF::StringImpl::toUInt64Strict):
+        (WTF::StringImpl::toIntPtrStrict):
+        (WTF::StringImpl::toInt):
+        (WTF::StringImpl::toUInt):
+        (WTF::StringImpl::toInt64):
+        (WTF::StringImpl::toUInt64):
+        (WTF::StringImpl::toIntPtr):
+        (WTF::StringImpl::toDouble):
+        (WTF::StringImpl::toFloat):
+        (WTF::equal):
+        (WTF::equalIgnoringCase):
+        (WTF::StringImpl::find):
+        (WTF::StringImpl::findIgnoringCase):
+        (WTF::StringImpl::reverseFind):
+        (WTF::StringImpl::replace):
+        (WTF::StringImpl::defaultWritingDirection):
+        (WTF::StringImpl::adopt):
+        (WTF::StringImpl::createWithTerminatingNullCharacter):
+        * wtf/text/StringImpl.h:
+        (WTF::StringImpl::StringImpl):
+        (WTF::StringImpl::create):
+        (WTF::StringImpl::create8):
+        (WTF::StringImpl::tryCreateUninitialized):
+        (WTF::StringImpl::flagsOffset):
+        (WTF::StringImpl::flagIs8Bit):
+        (WTF::StringImpl::dataOffset):
+        (WTF::StringImpl::is8Bit):
+        (WTF::StringImpl::characters8):
+        (WTF::StringImpl::characters16):
+        (WTF::StringImpl::characters):
+        (WTF::StringImpl::has16BitShadow):
+        (WTF::StringImpl::setHash):
+        (WTF::StringImpl::hash):
+        (WTF::StringImpl::copyChars):
+        (WTF::StringImpl::operator[]):
+        (WTF::StringImpl::find):
+        (WTF::StringImpl::findIgnoringCase):
+        (WTF::equal):
+        (WTF::equalIgnoringCase):
+        (WTF::StringImpl::isolatedCopy):
+        * wtf/text/WTFString.cpp:
+        (WTF::String::String):
+        (WTF::String::append):
+        (WTF::String::format):
+        (WTF::String::fromUTF8):
+        (WTF::String::fromUTF8WithLatin1Fallback):
+        * wtf/text/WTFString.h:
+        (WTF::String::find):
+        (WTF::String::findIgnoringCase):
+        (WTF::String::contains):
+        (WTF::String::append):
+        (WTF::String::fromUTF8):
+        (WTF::String::fromUTF8WithLatin1Fallback):
+        (WTF::operator==):
+        (WTF::operator!=):
+        (WTF::equalIgnoringCase):
+        * wtf/unicode/Unicode.h:
+        * yarr/YarrJIT.cpp:
+        (JSC::Yarr::execute):
+        * yarr/YarrJIT.h:
+        (JSC::Yarr::YarrCodeBlock::execute):
+        * yarr/YarrParser.h:
+        (JSC::Yarr::Parser::Parser):
+
 2011-10-27  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Fixing windows build
index 9db35ef..22cdd3d 100644 (file)
@@ -352,7 +352,6 @@ __ZN3JSCgtERKNS_7UStringES2_
 __ZN3JSCltERKNS_7UStringES2_
 __ZN3WTF10StringImpl11reverseFindEPS0_j
 __ZN3WTF10StringImpl11reverseFindEtj
-__ZN3WTF10StringImpl16findIgnoringCaseEPKcj
 __ZN3WTF10StringImpl16findIgnoringCaseEPS0_j
 __ZN3WTF10StringImpl18simplifyWhiteSpaceEv
 __ZN3WTF10StringImpl19characterStartingAtEj
@@ -362,7 +361,6 @@ __ZN3WTF10StringImpl23defaultWritingDirectionEPb
 __ZN3WTF10StringImpl23reverseFindIgnoringCaseEPS0_j
 __ZN3WTF10StringImpl4fillEt
 __ZN3WTF10StringImpl4findEPFbtEj
-__ZN3WTF10StringImpl4findEPKcj
 __ZN3WTF10StringImpl4findEPS0_j
 __ZN3WTF10StringImpl4findEtj
 __ZN3WTF10StringImpl5adoptERNS_12StringBufferE
@@ -370,8 +368,7 @@ __ZN3WTF10StringImpl5emptyEv
 __ZN3WTF10StringImpl5lowerEv
 __ZN3WTF10StringImpl5toIntEPb
 __ZN3WTF10StringImpl5upperEv
-__ZN3WTF10StringImpl6createEPKc
-__ZN3WTF10StringImpl6createEPKcj
+__ZN3WTF10StringImpl6createEPKh
 __ZN3WTF10StringImpl6createEPKtj
 __ZN3WTF10StringImpl7replaceEPS0_S1_
 __ZN3WTF10StringImpl7replaceEjjPS0_
@@ -391,7 +388,7 @@ __ZN3WTF11emptyStringEv
 __ZN3WTF11fastReallocEPvm
 __ZN3WTF12AtomicString11addSlowCaseEPNS_10StringImplE
 __ZN3WTF12AtomicString16fromUTF8InternalEPKcS2_
-__ZN3WTF12AtomicString3addEPKc
+__ZN3WTF12AtomicString3addEPKh
 __ZN3WTF12AtomicString3addEPKt
 __ZN3WTF12AtomicString3addEPKtj
 __ZN3WTF12AtomicString3addEPKtjj
@@ -433,9 +430,9 @@ __ZN3WTF16callOnMainThreadEPFvPvES0_
 __ZN3WTF16codePointCompareERKNS_6StringES2_
 __ZN3WTF16fastZeroedMallocEm
 __ZN3WTF17charactersToFloatEPKtmPbS2_
-__ZN3WTF17equalIgnoringCaseEPKtPKcj
-__ZN3WTF17equalIgnoringCaseEPNS_10StringImplEPKc
+__ZN3WTF17equalIgnoringCaseEPKtPKhj
 __ZN3WTF17equalIgnoringCaseEPNS_10StringImplES1_
+__ZN3WTF17equalIgnoringCaseEPNS_10StringImplEPKh
 __ZN3WTF18calculateDSTOffsetEdd
 __ZN3WTF18calculateUTCOffsetEv
 __ZN3WTF18charactersToDoubleEPKtmPbS2_
@@ -480,15 +477,16 @@ __ZN3WTF5Mutex6unlockEv
 __ZN3WTF5Mutex7tryLockEv
 __ZN3WTF5MutexC1Ev
 __ZN3WTF5MutexD1Ev
-__ZN3WTF5equalEPKNS_10StringImplEPKc
+__ZN3WTF5equalEPKNS_10StringImplEPKh
 __ZN3WTF5equalEPKNS_10StringImplEPKtj
 __ZN3WTF5equalEPKNS_10StringImplES2_
 __ZN3WTF5yieldEv
-__ZN3WTF6String26fromUTF8WithLatin1FallbackEPKcm
+__ZN3WTF6String26fromUTF8WithLatin1FallbackEPKhm
 __ZN3WTF6String29charactersWithNullTerminationEv
+__ZN3WTF6StringC1EPKcj
+__ZN3WTF6String6appendEh
 __ZN3WTF6String6appendEPKtj
 __ZN3WTF6String6appendERKS0_
-__ZN3WTF6String6appendEc
 __ZN3WTF6String6appendEt
 __ZN3WTF6String6formatEPKcz
 __ZN3WTF6String6insertERKS0_j
@@ -501,11 +499,10 @@ __ZN3WTF6String6numberEt
 __ZN3WTF6String6numberEx
 __ZN3WTF6String6numberEy
 __ZN3WTF6String6removeEji
-__ZN3WTF6String8fromUTF8EPKc
-__ZN3WTF6String8fromUTF8EPKcm
+__ZN3WTF6String8fromUTF8EPKh
+__ZN3WTF6String8fromUTF8EPKhm
 __ZN3WTF6String8truncateEj
 __ZN3WTF6StringC1EPKc
-__ZN3WTF6StringC1EPKcj
 __ZN3WTF6StringC1EPKt
 __ZN3WTF6StringC1EPKtj
 __ZN3WTF6strtodEPKcPPc
@@ -577,6 +574,7 @@ __ZNK3JSC8JSString11resolveRopeEPNS_9ExecStateE
 __ZNK3JSC8JSString9toBooleanEPNS_9ExecStateE
 __ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE
 __ZNK3JSC9HashTable11deleteTableEv
+__ZNK3WTF10StringImpl17getData16SlowCaseEv
 __ZNK3WTF12AtomicString5lowerEv
 __ZNK3WTF13DecimalNumber15toStringDecimalEPtj
 __ZNK3WTF13DecimalNumber19toStringExponentialEPtj
index f9c32d4..479470b 100644 (file)
@@ -47,6 +47,7 @@ EXPORTS
     ?ToShortest@DoubleToStringConverter@double_conversion@WTF@@QBE_NNPAVStringBuilder@23@@Z
     ?absoluteTimeToWaitTimeoutInterval@WTF@@YAKN@Z
     ?activityCallback@Heap@JSC@@QAEPAVGCActivityCallback@2@XZ
+    ?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBD@Z
     ?add@Identifier@JSC@@SA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PBD@Z
     ?add@PropertyNameArray@JSC@@QAEXPAVStringImpl@WTF@@@Z
     ?addBytes@MD5@WTF@@QAEXPBEI@Z
@@ -157,7 +158,6 @@ EXPORTS
     ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
     ?empty@StringImpl@WTF@@SAPAV12@XZ
     ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ
-    ?equal@Identifier@JSC@@SA_NPBVStringImpl@WTF@@PBD@Z
     ?equalUTF16WithUTF8@Unicode@WTF@@YA_NPB_W0PBD1@Z
     ?evaluate@DebuggerCallFrame@JSC@@QBE?AVJSValue@2@ABVUString@2@AAV32@@Z
     ?evaluate@JSC@@YA?AVJSValue@1@PAVExecState@1@PAVScopeChainNode@1@ABVSourceCode@1@V21@PAV21@@Z
index 0c51270..f193558 100644 (file)
@@ -445,7 +445,7 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r
         if (!codeBlock->isStrictMode()) {
             // FIXME: We can use the preparser in strict mode, we just need additional logic
             // to prevent duplicates.
-            LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
+            LiteralParser preparser(callFrame, programSource.characters16(), programSource.length(), LiteralParser::NonStrictJSON);
             if (JSValue parsedObject = preparser.tryLiteralParse())
                 return parsedObject;
         }
index 3b92b90..771e460 100644 (file)
@@ -88,17 +88,19 @@ namespace JSC {
         {
             return m_source.substringSharingImpl(start, end - start);
         }
-        const UChar* data() const { return m_source.characters(); }
+        const UChar* data() const { return m_data; }
         int length() const { return m_source.length(); }
 
     private:
         UStringSourceProvider(const UString& source, const UString& url)
             : SourceProvider(url)
             , m_source(source)
+            , m_data(m_source.characters16())
         {
         }
 
         UString m_source;
+        const UChar* m_data;
     };
     
 } // namespace JSC
index dcb6700..c4ed87b 100644 (file)
@@ -68,23 +68,23 @@ void deleteIdentifierTable(IdentifierTable* table)
 }
 
 struct IdentifierCStringTranslator {
-    static unsigned hash(const char* c)
+    static unsigned hash(const LChar* c)
     {
-        return StringHasher::computeHash<char>(c);
+        return StringHasher::computeHash<LChar>(c);
     }
 
-    static bool equal(StringImpl* r, const char* s)
+    static bool equal(StringImpl* r, const LChar* s)
     {
         return Identifier::equal(r, s);
     }
 
-    static void translate(StringImpl*& location, const char* c, unsigned hash)
+    static void translate(StringImpl*& location, const LChar* c, unsigned hash)
     {
-        size_t length = strlen(c);
+        size_t length = strlen(reinterpret_cast<const char*>(c));
         UChar* d;
         StringImpl* r = StringImpl::createUninitialized(length, d).leakRef();
         for (size_t i = 0; i != length; i++)
-            d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
+            d[i] = c[i];
         r->setHash(hash);
         location = r;
     }
@@ -97,7 +97,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
     if (!c[0])
         return StringImpl::empty();
     if (!c[1])
-        return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0])));
+        return add(globalData, globalData->smallStrings.singleCharacterStringRep(c[0]));
 
     IdentifierTable& identifierTable = *globalData->identifierTable;
     LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable();
@@ -106,7 +106,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
     if (iter != literalIdentifierTable.end())
         return iter->second;
 
-    pair<HashSet<StringImpl*>::iterator, bool> addResult = identifierTable.add<const char*, IdentifierCStringTranslator>(c);
+    pair<HashSet<StringImpl*>::iterator, bool> addResult = identifierTable.add<const LChar*, IdentifierCStringTranslator>(reinterpret_cast<const LChar*>(c));
 
     // If the string is newly-translated, then we need to adopt it.
     // The boolean in the pair tells us if that is so.
@@ -154,12 +154,13 @@ uint32_t Identifier::toUInt32(const UString& string, bool& ok)
     ok = false;
 
     unsigned length = string.length();
-    const UChar* characters = string.characters();
 
     // An empty string is not a number.
     if (!length)
         return 0;
 
+    const UChar* characters = string.characters16();
+
     // Get the first character, turning it into a digit.
     uint32_t value = characters[0] - '0';
     if (value > 9)
index 39986ae..74fc453 100644 (file)
@@ -70,10 +70,13 @@ namespace JSC {
         friend bool operator==(const Identifier&, const Identifier&);
         friend bool operator!=(const Identifier&, const Identifier&);
 
+        friend bool operator==(const Identifier&, const LChar*);
         friend bool operator==(const Identifier&, const char*);
+        friend bool operator!=(const Identifier&, const LChar*);
         friend bool operator!=(const Identifier&, const char*);
     
-        static bool equal(const StringImpl*, const char*);
+        static bool equal(const StringImpl*, const LChar*);
+        static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
         static bool equal(const StringImpl*, const UChar*, unsigned length);
         static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
 
@@ -84,7 +87,7 @@ namespace JSC {
         UString m_string;
         
         static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
-        static bool equal(const Identifier& a, const char* b) { return equal(a.m_string.impl(), b); }
+        static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
 
         static PassRefPtr<StringImpl> add(ExecState*, const UChar*, int length);
         static PassRefPtr<StringImpl> add(JSGlobalData*, const UChar*, int length);
@@ -125,17 +128,27 @@ namespace JSC {
         return !Identifier::equal(a, b);
     }
 
-    inline bool operator==(const Identifier& a, const char* b)
+    inline bool operator==(const Identifier& a, const LChar* b)
     {
         return Identifier::equal(a, b);
     }
 
-    inline bool operator!=(const Identifier& a, const char* b)
+    inline bool operator==(const Identifier& a, const char* b)
+    {
+        return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+    }
+    
+    inline bool operator!=(const Identifier& a, const LChar* b)
     {
         return !Identifier::equal(a, b);
     }
 
-    inline bool Identifier::equal(const StringImpl* r, const char* s)
+    inline bool operator!=(const Identifier& a, const char* b)
+    {
+        return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+    }
+    
+    inline bool Identifier::equal(const StringImpl* r, const LChar* s)
     {
         return WTF::equal(r, s);
     }
index f570634..a982f19 100644 (file)
@@ -79,7 +79,7 @@ void JSString::resolveRope(ExecState* exec) const
     for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
         StringImpl* string = m_fibers[i]->m_value.impl();
         unsigned length = string->length();
-        StringImpl::copyChars(position, string->characters(), length);
+        StringImpl::copyChars(position, string->characters16(), length);
         position += length;
         m_fibers[i].clear();
     }
@@ -120,7 +120,7 @@ void JSString::resolveRopeSlowCase(ExecState* exec, UChar* buffer) const
         StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
         unsigned length = string->length();
         position -= length;
-        StringImpl::copyChars(position, string->characters(), length);
+        StringImpl::copyChars(position, string->characters16(), length);
     }
 
     ASSERT(buffer == position);
index 9f28c7c..05df32b 100644 (file)
@@ -366,9 +366,9 @@ int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, V
 #if ENABLE(YARR_JIT)
         if (m_state == JITCode) {
             if (s.is8Bit())
-                result = Yarr::execute(m_representation->m_regExpJITCode, s.latin1().data(), startOffset, s.length(), offsetVector);
+                result = Yarr::execute(m_representation->m_regExpJITCode, s.characters8(), startOffset, s.length(), offsetVector);
             else
-                result = Yarr::execute(m_representation->m_regExpJITCode, s.characters(), startOffset, s.length(), offsetVector);
+                result = Yarr::execute(m_representation->m_regExpJITCode, s.characters16(), startOffset, s.length(), offsetVector);
 #if ENABLE(YARR_JIT_DEBUG)
             matchCompareWithInterpreter(s, startOffset, offsetVector, result);
 #endif
index 834d0d7..44f040c 100644 (file)
@@ -330,13 +330,13 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
     for (int i = 0; i < maxCount; i++) {
         if (i < rangeCount) {
             if (int srcLen = substringRanges[i].length) {
-                StringImpl::copyChars(buffer + bufferPos, source.characters() + substringRanges[i].position, srcLen);
+                StringImpl::copyChars(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
                 bufferPos += srcLen;
             }
         }
         if (i < separatorCount) {
             if (int sepLen = separators[i].length()) {
-                StringImpl::copyChars(buffer + bufferPos, separators[i].characters(), sepLen);
+                StringImpl::copyChars(buffer + bufferPos, separators[i].characters16(), sepLen);
                 bufferPos += sepLen;
             }
         }
index b78e6f1..2447765 100644 (file)
@@ -73,17 +73,27 @@ UString::UString(const UChar* characters)
 }
 
 // Construct a string with latin1 data.
-UString::UString(const char* characters, unsigned length)
+UString::UString(const LChar* characters, unsigned length)
     : m_impl(characters ? StringImpl::create(characters, length) : 0)
 {
 }
 
+UString::UString(const char* characters, unsigned length)
+    : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters), length) : 0)
+{
+}
+
 // Construct a string with latin1 data, from a null-terminated source.
-UString::UString(const char* characters)
+UString::UString(const LChar* characters)
     : m_impl(characters ? StringImpl::create(characters) : 0)
 {
 }
 
+UString::UString(const char* characters)
+    : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters)) : 0)
+{
+}
+
 UString UString::number(int i)
 {
     UChar buf[1 + sizeof(i) * 3];
@@ -229,6 +239,77 @@ bool operator==(const UString& s1, const char *s2)
     return u == uend && *s2 == 0;
 }
 
+// This method assumes that all simple checks have been performed by
+// the inlined operator==() in the header file.
+bool equalSlowCase(const UString& s1, const UString& s2)
+{
+    StringImpl* rep1 = s1.impl();
+    StringImpl* rep2 = s2.impl();
+    unsigned size1 = rep1->length();
+
+    // At this point we know 
+    //   (a) that the strings are the same length and
+    //   (b) that they are greater than zero length.
+    bool s1Is8Bit = rep1->is8Bit();
+    bool s2Is8Bit = rep2->is8Bit();
+    
+    if (s1Is8Bit) {
+        const LChar* d1 = rep1->characters8();
+        if (s2Is8Bit) {
+            const LChar* d2 = rep2->characters8();
+            
+            if (d1 == d2) // Check to see if the data pointers are the same.
+                return true;
+            
+            // Do quick checks for sizes 1 and 2.
+            switch (size1) {
+            case 1:
+                return d1[0] == d2[0];
+            case 2:
+                return (d1[0] == d2[0]) & (d1[1] == d2[1]);
+            default:
+                return (!memcmp(d1, d2, size1 * sizeof(LChar)));
+            }
+        }
+        
+        const UChar* d2 = rep2->characters16();
+        
+        for (unsigned i = 0; i < size1; i++) {
+            if (d1[i] != d2[i])
+                return false;
+        }
+        return true;
+    }
+    
+    if (s2Is8Bit) {
+        const UChar* d1 = rep1->characters16();
+        const LChar* d2 = rep2->characters8();
+        
+        for (unsigned i = 0; i < size1; i++) {
+            if (d1[i] != d2[i])
+                return false;
+        }
+        return true;
+        
+    }
+    
+    const UChar* d1 = rep1->characters16();
+    const UChar* d2 = rep2->characters16();
+    
+    if (d1 == d2) // Check to see if the data pointers are the same.
+        return true;
+    
+    // Do quick checks for sizes 1 and 2.
+    switch (size1) {
+    case 1:
+        return d1[0] == d2[0];
+    case 2:
+        return (d1[0] == d2[0]) & (d1[1] == d2[1]);
+    default:
+        return (!memcmp(d1, d2, size1 * sizeof(UChar)));
+    }
+}
+
 bool operator<(const UString& s1, const UString& s2)
 {
     const unsigned l1 = s1.length();
@@ -317,7 +398,9 @@ static inline void putUTF8Triple(char*& buffer, UChar ch)
 CString UString::utf8(bool strict) const
 {
     unsigned length = this->length();
-    const UChar* characters = this->characters();
+
+    if (is8Bit())
+        return CString(reinterpret_cast<const char*>(characters8()), length);
 
     // Allocate a buffer big enough to hold all the characters
     // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes).
@@ -331,6 +414,8 @@ CString UString::utf8(bool strict) const
     //    buffer without reallocing (say, 1.5 x length).
     if (length > numeric_limits<unsigned>::max() / 3)
         return CString();
+
+    const UChar* characters = this->characters16();
     Vector<char, 1024> bufferVector(length * 3);
 
     char* buffer = bufferVector.data();
index 0954e65..0e0360f 100644 (file)
@@ -39,9 +39,11 @@ public:
     UString(const UChar*);
 
     // Construct a string with latin1 data.
+    UString(const LChar* characters, unsigned length);
     UString(const char* characters, unsigned length);
 
     // Construct a string with latin1 data, from a null-terminated source.
+    UString(const LChar* characters);
     UString(const char* characters);
 
     // Construct a string referencing an existing StringImpl.
@@ -73,10 +75,26 @@ public:
     {
         if (!m_impl)
             return 0;
-        return m_impl->characters();
+        return m_impl->characters16();
     }
 
-    bool is8Bit() const { return false; }
+    const LChar* characters8() const
+    {
+        if (!m_impl)
+            return 0;
+        ASSERT(m_impl->is8Bit());
+        return m_impl->characters8();
+    }
+
+    const UChar* characters16() const
+    {
+        if (!m_impl)
+            return 0;
+        ASSERT(!m_impl->is8Bit());
+        return m_impl->characters16();
+    }
+
+    bool is8Bit() const { return m_impl->is8Bit(); }
 
     CString ascii() const;
     CString latin1() const;
@@ -86,7 +104,9 @@ public:
     {
         if (!m_impl || index >= m_impl->length())
             return 0;
-        return m_impl->characters()[index];
+        if (is8Bit())
+            return m_impl->characters8()[index];
+        return m_impl->characters16()[index];
     }
 
     static UString number(int);
@@ -100,7 +120,7 @@ public:
         { return m_impl ? m_impl->find(c, start) : notFound; }
     size_t find(const UString& str, unsigned start = 0) const
         { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
-    size_t find(const char* str, unsigned start = 0) const
+    size_t find(const LChar* str, unsigned start = 0) const
         { return m_impl ? m_impl->find(str, start) : notFound; }
 
     // Find the last instance of a single character or string.
@@ -115,46 +135,35 @@ private:
     RefPtr<StringImpl> m_impl;
 };
 
+NEVER_INLINE bool equalSlowCase(const UString& s1, const UString& s2);
+
 ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
 {
     StringImpl* rep1 = s1.impl();
     StringImpl* rep2 = s2.impl();
-    unsigned size1 = 0;
-    unsigned size2 = 0;
 
     if (rep1 == rep2) // If they're the same rep, they're equal.
         return true;
-    
+
+    unsigned size1 = 0;
+    unsigned size2 = 0;
+
     if (rep1)
         size1 = rep1->length();
-        
+
     if (rep2)
         size2 = rep2->length();
-        
+
     if (size1 != size2) // If the lengths are not the same, we're done.
         return false;
-    
+
     if (!size1)
         return true;
-    
-    // At this point we know 
-    //   (a) that the strings are the same length and
-    //   (b) that they are greater than zero length.
-    const UChar* d1 = rep1->characters();
-    const UChar* d2 = rep2->characters();
-    
-    if (d1 == d2) // Check to see if the data pointers are the same.
-        return true;
-    
-    // Do quick checks for sizes 1 and 2.
-    switch (size1) {
-    case 1:
-        return d1[0] == d2[0];
-    case 2:
-        return (d1[0] == d2[0]) & (d1[1] == d2[1]);
-    default:
-        return memcmp(d1, d2, size1 * sizeof(UChar)) == 0;
-    }
+
+    if (size1 == 1)
+        return (*rep1)[0] == (*rep2)[0];
+
+    return equalSlowCase(s1, s2);
 }
 
 
index a2c9b49..7145251 100644 (file)
@@ -134,12 +134,12 @@ public:
 
     template<typename T> static inline unsigned computeHash(const T* data, unsigned length)
     {
-        return computeHash<T, defaultCoverter>(data, length);
+        return computeHash<T, defaultConverter>(data, length);
     }
 
     template<typename T> static inline unsigned computeHash(const T* data)
     {
-        return computeHash<T, defaultCoverter>(data);
+        return computeHash<T, defaultConverter>(data);
     }
 
     template<size_t length> static inline unsigned hashMemory(const void* data)
@@ -155,14 +155,14 @@ public:
     }
 
 private:
-    static inline UChar defaultCoverter(UChar ch)
+    static inline UChar defaultConverter(UChar ch)
     {
         return ch;
     }
 
-    static inline UChar defaultCoverter(char ch)
+    static inline UChar defaultConverter(LChar ch)
     {
-        return static_cast<unsigned char>(ch);
+        return ch;
     }
 
     inline void addCharactersToHash(UChar a, UChar b)
index 7e45695..7d8dd15 100644 (file)
@@ -85,17 +85,17 @@ static inline PassRefPtr<StringImpl> addToStringTable(const T& value)
 }
 
 struct CStringTranslator {
-    static unsigned hash(const char* c)
+    static unsigned hash(const LChar* c)
     {
         return StringHasher::computeHash(c);
     }
 
-    static inline bool equal(StringImpl* r, const char* s)
+    static inline bool equal(StringImpl* r, const LChar* s)
     {
         return WTF::equal(r, s);
     }
 
-    static void translate(StringImpl*& location, const char* const& c, unsigned hash)
+    static void translate(StringImpl*& location, const LChar* const& c, unsigned hash)
     {
         location = StringImpl::create(c).leakRef();
         location->setHash(hash);
@@ -103,14 +103,14 @@ struct CStringTranslator {
     }
 };
 
-PassRefPtr<StringImpl> AtomicString::add(const char* c)
+PassRefPtr<StringImpl> AtomicString::add(const LChar* c)
 {
     if (!c)
         return 0;
     if (!*c)
         return StringImpl::empty();
 
-    return addToStringTable<const char*, CStringTranslator>(c);
+    return addToStringTable<const LChar*, CStringTranslator>(c);
 }
 
 struct UCharBuffer {
index cbad4f7..72c8cf4 100644 (file)
@@ -41,6 +41,7 @@ public:
     static void init();
 
     AtomicString() { }
+    AtomicString(const LChar* s) : m_string(add(s)) { }
     AtomicString(const char* s) : m_string(add(s)) { }
     AtomicString(const UChar* s, unsigned length) : m_string(add(s, length)) { }
     AtomicString(const UChar* s, unsigned length, unsigned existingHash) : m_string(add(s, length, existingHash)) { }
@@ -66,13 +67,13 @@ public:
     UChar operator[](unsigned int i) const { return m_string[i]; }
     
     bool contains(UChar c) const { return m_string.contains(c); }
-    bool contains(const char* s, bool caseSensitive = true) const
+    bool contains(const LChar* s, bool caseSensitive = true) const
         { return m_string.contains(s, caseSensitive); }
     bool contains(const String& s, bool caseSensitive = true) const
         { return m_string.contains(s, caseSensitive); }
 
     size_t find(UChar c, size_t start = 0) const { return m_string.find(c, start); }
-    size_t find(const char* s, size_t start = 0, bool caseSentitive = true) const
+    size_t find(const LChar* s, size_t start = 0, bool caseSentitive = true) const
         { return m_string.find(s, start, caseSentitive); }
     size_t find(const String& s, size_t start = 0, bool caseSentitive = true) const
         { return m_string.find(s, start, caseSentitive); }
@@ -119,8 +120,10 @@ public:
 private:
     String m_string;
     
-    static PassRefPtr<StringImpl> add(const char*);
+    static PassRefPtr<StringImpl> add(const LChar*);
+    ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s) { return add(reinterpret_cast<const LChar*>(s)); };
     static PassRefPtr<StringImpl> add(const UChar*, unsigned length);
+    ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const char*>(s), length); };
     static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash);
     static PassRefPtr<StringImpl> add(const UChar*);
     ALWAYS_INLINE PassRefPtr<StringImpl> add(StringImpl* r)
@@ -134,26 +137,29 @@ private:
 };
 
 inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
-bool operator==(const AtomicString& a, const char* b);
-inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), b); }
+bool operator==(const AtomicString&, const LChar*);
+inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
 inline bool operator==(const AtomicString& a, const Vector<UChar>& b) { return a.impl() && equal(a.impl(), b.data(), b.size()); }    
 inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); }
-inline bool operator==(const char* a, const AtomicString& b) { return b == a; }
+inline bool operator==(const LChar* a, const AtomicString& b) { return b == a; }
 inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); }
 inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; }
 
 inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); }
-inline bool operator!=(const AtomicString& a, const char *b) { return !(a == b); }
+inline bool operator!=(const AtomicString& a, const LChar* b) { return !(a == b); }
+inline bool operator!=(const AtomicString& a, const char* b) { return !(a == b); }
 inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); }
 inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); }
-inline bool operator!=(const char* a, const AtomicString& b) { return !(b == a); }
+inline bool operator!=(const LChar* a, const AtomicString& b) { return !(b == a); }
 inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); }
 inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); }
 
 inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); }
-inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), b); }
+inline bool equalIgnoringCase(const AtomicString& a, const LChar* b) { return equalIgnoringCase(a.impl(), b); }
+inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); }
 inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); }
-inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const LChar* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(a), b.impl()); }
 inline bool equalIgnoringCase(const String& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); }
 
 // Define external global variables for the commonly used atomic strings.
index d3f2376..49c8df6 100644 (file)
@@ -58,6 +58,21 @@ private:
 };
 
 template<>
+class StringTypeAdapter<LChar> {
+public:
+    StringTypeAdapter<LChar>(LChar buffer)
+        : m_buffer(buffer)
+    {
+    }
+
+    unsigned length() { return 1; }
+    void writeTo(UChar* destination) { *destination = m_buffer; }
+
+private:
+    LChar m_buffer;
+};
+
+template<>
 class StringTypeAdapter<UChar> {
 public:
     StringTypeAdapter<UChar>(UChar buffer)
@@ -97,6 +112,28 @@ private:
 };
 
 template<>
+class StringTypeAdapter<LChar*> {
+public:
+    StringTypeAdapter<LChar*>(LChar* buffer)
+    : m_buffer(buffer)
+    , m_length(strlen(reinterpret_cast<char*>(buffer)))
+    {
+    }
+
+    unsigned length() { return m_length; }
+
+    void writeTo(UChar* destination)
+    {
+        for (unsigned i = 0; i < m_length; ++i)
+            destination[i] = m_buffer[i];
+    }
+
+private:
+    const LChar* m_buffer;
+    unsigned m_length;
+};
+
+template<>
 class StringTypeAdapter<const UChar*> {
 public:
     StringTypeAdapter<const UChar*>(const UChar* buffer)
@@ -149,6 +186,28 @@ private:
 };
 
 template<>
+class StringTypeAdapter<const LChar*> {
+public:
+    StringTypeAdapter<const LChar*>(const LChar* buffer)
+        : m_buffer(buffer)
+        , m_length(strlen(reinterpret_cast<const char*>(buffer)))
+    {
+    }
+    
+    unsigned length() { return m_length; }
+    
+    void writeTo(UChar* destination)
+    {
+        for (unsigned i = 0; i < m_length; ++i)
+            destination[i] = m_buffer[i];
+    }
+    
+private:
+    const LChar* m_buffer;
+    unsigned m_length;
+};
+
+template<>
 class StringTypeAdapter<Vector<char> > {
 public:
     StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
@@ -171,6 +230,26 @@ private:
 };
 
 template<>
+class StringTypeAdapter<Vector<LChar> > {
+public:
+    StringTypeAdapter<Vector<LChar> >(const Vector<LChar>& buffer)
+        : m_buffer(buffer)
+    {
+    }
+
+    size_t length() { return m_buffer.size(); }
+
+    void writeTo(UChar* destination)
+    {
+        for (size_t i = 0; i < m_buffer.size(); ++i)
+            destination[i] = m_buffer[i];
+    }
+
+private:
+    const Vector<LChar>& m_buffer;
+};
+
+template<>
 class StringTypeAdapter<String> {
 public:
     StringTypeAdapter<String>(const String& string)
index b30464b..1a40276 100644 (file)
@@ -53,11 +53,67 @@ namespace WTF {
             if (aLength != bLength)
                 return false;
 
+            if (a->is8Bit()) {
+                if (b->is8Bit()) {
+                    // Both a & b are 8 bit.
+                    const LChar* aChars = a->characters8();
+                    const LChar* bChars = b->characters8();
+
+                    unsigned i = 0;
+
+                    // FIXME: perhaps we should have a more abstract macro that indicates when
+                    // going 4 bytes at a time is unsafe
+#if (CPU(X86) || CPU(X86_64))
+                    const unsigned charsPerInt = sizeof(uint32_t) / sizeof(char);
+                    
+                    if (aLength > charsPerInt) {
+                        unsigned stopCount = aLength & ~(charsPerInt - 1);
+                        
+                        const uint32_t* aIntCharacters = reinterpret_cast<const uint32_t*>(aChars);
+                        const uint32_t* bIntCharacters = reinterpret_cast<const uint32_t*>(bChars);
+                        for (unsigned j = 0; i < stopCount; i += charsPerInt, ++j) {
+                            if (aIntCharacters[j] != bIntCharacters[j])
+                                return false;
+                        }
+                    }
+#endif
+                    for (; i < aLength; ++i) {
+                        if (aChars[i] != bChars[i])
+                            return false;
+                    }
+                    
+                    return true;
+                }
+
+                // We know that a is 8 bit & b is 16 bit.
+                const LChar* aChars = a->characters8();
+                const UChar* bChars = b->characters16();
+                for (unsigned i = 0; i != aLength; ++i) {
+                    if (*aChars++ != *bChars++)
+                        return false;
+                }
+
+                return true;
+            }
+
+            if (b->is8Bit()) {
+                // We know that a is 8 bit and b is 16 bit.
+                const UChar* aChars = a->characters16();
+                const LChar* bChars = b->characters8();
+                for (unsigned i = 0; i != aLength; ++i) {
+                    if (*aChars++ != *bChars++)
+                        return false;
+                }
+
+                return true;
+            }
+
+            // Both a & b are 16 bit.
             // FIXME: perhaps we should have a more abstract macro that indicates when
             // going 4 bytes at a time is unsafe
 #if CPU(ARM) || CPU(SH4) || CPU(MIPS) || CPU(SPARC)
-            const UChar* aChars = a->characters();
-            const UChar* bChars = b->characters();
+            const UChar* aChars = a->characters16();
+            const UChar* bChars = b->characters16();
             for (unsigned i = 0; i != aLength; ++i) {
                 if (*aChars++ != *bChars++)
                     return false;
@@ -65,8 +121,8 @@ namespace WTF {
             return true;
 #else
             /* Do it 4-bytes-at-a-time on architectures where it's safe */
-            const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters());
-            const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters());
+            const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters16());
+            const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters16());
 
             unsigned halfLength = aLength >> 1;
             for (unsigned i = 0; i != halfLength; ++i)
@@ -112,11 +168,16 @@ namespace WTF {
             return hash(str->characters(), str->length());
         }
 
-        static unsigned hash(const char* data, unsigned length)
+        static unsigned hash(const LChar* data, unsigned length)
         {
-            return StringHasher::computeHash<char, foldCase<char> >(data, length);
+            return StringHasher::computeHash<LChar, foldCase<LChar> >(data, length);
         }
 
+        static inline unsigned hash(const char* data, unsigned length)
+        {
+            return CaseFoldingHash::hash(reinterpret_cast<const LChar*>(data), length);
+        }
+        
         static bool equal(const StringImpl* a, const StringImpl* b)
         {
             if (a == b)
index 1073925..4fb29fa 100644 (file)
@@ -55,11 +55,18 @@ StringImpl::~StringImpl()
 #endif
 
     BufferOwnership ownership = bufferOwnership();
+
+    if (has16BitShadow()) {
+        ASSERT(m_copyData16);
+        fastFree(m_copyData16);
+    }
+
     if (ownership == BufferInternal)
         return;
     if (ownership == BufferOwned) {
-        ASSERT(m_data);
-        fastFree(const_cast<UChar*>(m_data));
+        // We use m_data8, but since it is a union with m_data16 this works either way.
+        ASSERT(m_data8);
+        fastFree(const_cast<LChar*>(m_data8));
         return;
     }
 
@@ -68,6 +75,25 @@ StringImpl::~StringImpl()
     m_substringBuffer->deref();
 }
 
+PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, LChar*& data)
+{
+    if (!length) {
+        data = 0;
+        return empty();
+    }
+
+    // Allocate a single buffer large enough to contain the StringImpl
+    // struct as well as the data which it contains. This removes one
+    // heap allocation from this call.
+    if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(LChar)))
+        CRASH();
+    size_t size = sizeof(StringImpl) + length * sizeof(LChar);
+    StringImpl* string = static_cast<StringImpl*>(fastMalloc(size));
+
+    data = reinterpret_cast<LChar*>(string + 1);
+    return adoptRef(new (string) StringImpl(length, Force8BitConstructor));
+}
+
 PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& data)
 {
     if (!length) {
@@ -118,7 +144,7 @@ PassRefPtr<StringImpl> StringImpl::create(const UChar* characters, unsigned leng
     return string.release();
 }
 
-PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned length)
+PassRefPtr<StringImpl> StringImpl::create(const LChar* characters, unsigned length)
 {
     if (!characters || !length)
         return empty();
@@ -132,24 +158,58 @@ PassRefPtr<StringImpl> StringImpl::create(const char* characters, unsigned lengt
     return string.release();
 }
 
-PassRefPtr<StringImpl> StringImpl::create(const char* string)
+PassRefPtr<StringImpl> StringImpl::create(const LChar* string)
 {
     if (!string)
         return empty();
-    size_t length = strlen(string);
+    size_t length = strlen(reinterpret_cast<const char*>(string));
     if (length > numeric_limits<unsigned>::max())
         CRASH();
     return create(string, length);
 }
 
+const UChar* StringImpl::getData16SlowCase() const
+{
+    if (has16BitShadow())
+        return m_copyData16;
+
+    if (bufferOwnership() == BufferSubstring) {
+        // If this is a substring, return a pointer into the parent string.
+        // TODO: Consider severing this string from the parent string
+        unsigned offset = m_data8 - m_substringBuffer->characters8();
+        return m_substringBuffer->characters16() + offset;
+    }
+
+    unsigned len = length();
+    m_copyData16 = static_cast<UChar*>(fastMalloc(len * sizeof(UChar)));
+    for (size_t i = 0; i < len; i++)
+        m_copyData16[i] = m_data8[i];
+
+    m_hashAndFlags |= s_hashFlagHas16BitShadow;
+
+    return m_copyData16;
+}
+
 bool StringImpl::containsOnlyWhitespace()
 {
     // FIXME: The definition of whitespace here includes a number of characters
     // that are not whitespace from the point of view of RenderText; I wonder if
     // that's a problem in practice.
-    for (unsigned i = 0; i < m_length; i++)
-        if (!isASCIISpace(m_data[i]))
+    if (is8Bit()) {
+        for (unsigned i = 0; i < m_length; i++) {
+            UChar c = m_data8[i];
+            if (!isASCIISpace(c))
+                return false;
+        }
+
+        return true;
+    }
+
+    for (unsigned i = 0; i < m_length; i++) {
+        UChar c = m_data16[i];
+        if (!isASCIISpace(c))
             return false;
+    }
     return true;
 }
 
@@ -163,15 +223,20 @@ PassRefPtr<StringImpl> StringImpl::substring(unsigned start, unsigned length)
             return this;
         length = maxLength;
     }
-    return create(m_data + start, length);
+    if (is8Bit())
+        return create(m_data8 + start, length);
+
+    return create(m_data16 + start, length);
 }
 
 UChar32 StringImpl::characterStartingAt(unsigned i)
 {
-    if (U16_IS_SINGLE(m_data[i]))
-        return m_data[i];
-    if (i + 1 < m_length && U16_IS_LEAD(m_data[i]) && U16_IS_TRAIL(m_data[i + 1]))
-        return U16_GET_SUPPLEMENTARY(m_data[i], m_data[i + 1]);
+    if (is8Bit())
+        return m_data8[i];
+    if (U16_IS_SINGLE(m_data16[i]))
+        return m_data16[i];
+    if (i + 1 < m_length && U16_IS_LEAD(m_data16[i]) && U16_IS_TRAIL(m_data16[i + 1]))
+        return U16_GET_SUPPLEMENTARY(m_data16[i], m_data16[i + 1]);
     return 0;
 }
 
@@ -181,15 +246,46 @@ PassRefPtr<StringImpl> StringImpl::lower()
     // no-op code path up through the first 'return' statement.
     
     // First scan the string for uppercase and non-ASCII characters:
-    UChar ored = 0;
     bool noUpper = true;
-    const UChar *end = m_data + m_length;
-    for (const UChar* chp = m_data; chp != end; chp++) {
+    UChar ored = 0;
+    if (is8Bit()) {
+        const LChar* end = m_data8 + m_length;
+        for (const LChar* chp = m_data8; chp != end; chp++) {
+            if (UNLIKELY(isASCIIUpper(*chp)))
+                noUpper = false;
+            ored |= *chp;
+        }
+        // Nothing to do if the string is all ASCII with no uppercase.
+        if (noUpper && !(ored & ~0x7F))
+            return this;
+
+        if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max()))
+            CRASH();
+        int32_t length = m_length;
+
+        LChar* data8;
+        RefPtr<StringImpl> newImpl = createUninitialized(length, data8);
+
+        if (!(ored & ~0x7F)) {
+            for (int32_t i = 0; i < length; i++)
+                data8[i] = toASCIILower(m_data8[i]);
+
+            return newImpl.release();
+        }
+
+        // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+        for (int32_t i = 0; i < length; i++)
+            data8[i] = static_cast<LChar>(Unicode::toLower(m_data8[i]));
+
+        return newImpl.release();
+    }
+
+    const UChar *end = m_data16 + m_length;
+    for (const UChar* chp = m_data16; chp != end; chp++) {
         if (UNLIKELY(isASCIIUpper(*chp)))
             noUpper = false;
         ored |= *chp;
     }
-    
     // Nothing to do if the string is all ASCII with no uppercase.
     if (noUpper && !(ored & ~0x7F))
         return this;
@@ -198,28 +294,31 @@ PassRefPtr<StringImpl> StringImpl::lower()
         CRASH();
     int32_t length = m_length;
 
-    UChar* data;
-    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
-
     if (!(ored & ~0x7F)) {
-        // Do a faster loop for the case where all the characters are ASCII.
-        for (int i = 0; i < length; i++) {
-            UChar c = m_data[i];
-            data[i] = toASCIILower(c);
+        UChar* data16;
+        RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+        
+        for (int32_t i = 0; i < length; i++) {
+            UChar c = m_data16[i];
+            data16[i] = toASCIILower(c);
         }
-        return newImpl;
+        return newImpl.release();
     }
     
     // Do a slower implementation for cases that include non-ASCII characters.
+    UChar* data16;
+    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+
     bool error;
-    int32_t realLength = Unicode::toLower(data, length, m_data, m_length, &error);
+    int32_t realLength = Unicode::toLower(data16, length, m_data16, m_length, &error);
     if (!error && realLength == length)
-        return newImpl;
-    newImpl = createUninitialized(realLength, data);
-    Unicode::toLower(data, realLength, m_data, m_length, &error);
+        return newImpl.release();
+
+    newImpl = createUninitialized(realLength, data16);
+    Unicode::toLower(data16, realLength, m_data16, m_length, &error);
     if (error)
         return this;
-    return newImpl;
+    return newImpl.release();
 }
 
 PassRefPtr<StringImpl> StringImpl::upper()
@@ -227,30 +326,53 @@ PassRefPtr<StringImpl> StringImpl::upper()
     // This function could be optimized for no-op cases the way lower() is,
     // but in empirical testing, few actual calls to upper() are no-ops, so
     // it wouldn't be worth the extra time for pre-scanning.
-    UChar* data;
-    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
 
     if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max()))
         CRASH();
     int32_t length = m_length;
 
+    if (is8Bit()) {
+        LChar* data8;
+        RefPtr<StringImpl> newImpl = createUninitialized(m_length, data8);
+        
+        // Do a faster loop for the case where all the characters are ASCII.
+        char ored = 0;
+        for (int i = 0; i < length; i++) {
+            char c = m_data8[i];
+            ored |= c;
+            data8[i] = toASCIIUpper(c);
+        }
+        if (!(ored & ~0x7F))
+            return newImpl.release();
+
+        // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+        for (int32_t i = 0; i < length; i++)
+            data8[i] = static_cast<LChar>(Unicode::toUpper(m_data8[i]));
+
+        return newImpl.release();
+    }
+
+    UChar* data16;
+    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data16);
+    
     // Do a faster loop for the case where all the characters are ASCII.
     UChar ored = 0;
     for (int i = 0; i < length; i++) {
-        UChar c = m_data[i];
+        UChar c = m_data16[i];
         ored |= c;
-        data[i] = toASCIIUpper(c);
+        data16[i] = toASCIIUpper(c);
     }
     if (!(ored & ~0x7F))
         return newImpl.release();
 
     // Do a slower implementation for cases that include non-ASCII characters.
     bool error;
-    int32_t realLength = Unicode::toUpper(data, length, m_data, m_length, &error);
+    newImpl = createUninitialized(m_length, data16);
+    int32_t realLength = Unicode::toUpper(data16, length, m_data16, m_length, &error);
     if (!error && realLength == length)
         return newImpl;
-    newImpl = createUninitialized(realLength, data);
-    Unicode::toUpper(data, realLength, m_data, m_length, &error);
+    newImpl = createUninitialized(realLength, data16);
+    Unicode::toUpper(data16, realLength, m_data16, m_length, &error);
     if (error)
         return this;
     return newImpl.release();
@@ -261,6 +383,13 @@ PassRefPtr<StringImpl> StringImpl::fill(UChar character)
     if (!m_length)
         return this;
 
+    if (!(character & ~0x7F)) {
+        LChar* data;
+        RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+        for (unsigned i = 0; i < m_length; ++i)
+            data[i] = character;
+        return newImpl.release();
+    }
     UChar* data;
     RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
     for (unsigned i = 0; i < m_length; ++i)
@@ -270,17 +399,36 @@ PassRefPtr<StringImpl> StringImpl::fill(UChar character)
 
 PassRefPtr<StringImpl> StringImpl::foldCase()
 {
-    UChar* data;
-    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
-
     if (m_length > static_cast<unsigned>(numeric_limits<int32_t>::max()))
         CRASH();
     int32_t length = m_length;
 
+    if (is8Bit()) {
+        // Do a faster loop for the case where all the characters are ASCII.
+        LChar* data;
+        RefPtr <StringImpl>newImpl = createUninitialized(m_length, data);
+        LChar ored = 0;
+
+        for (int32_t i = 0; i < length; i++) {
+            LChar c = m_data8[i];
+            data[i] = toASCIILower(c);
+            ored |= c;
+        }
+
+        if (!(ored & ~0x7F))
+            return newImpl.release();
+
+        // Do a slower implementation for cases that include non-ASCII Latin-1 characters.
+        for (int32_t i = 0; i < length; i++)
+            data[i] = static_cast<LChar>(Unicode::toLower(m_data8[i]));
+    }
+
     // Do a faster loop for the case where all the characters are ASCII.
+    UChar* data;
+    RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
     UChar ored = 0;
     for (int32_t i = 0; i < length; i++) {
-        UChar c = m_data[i];
+        UChar c = m_data16[i];
         ored |= c;
         data[i] = toASCIILower(c);
     }
@@ -289,11 +437,11 @@ PassRefPtr<StringImpl> StringImpl::foldCase()
 
     // Do a slower implementation for cases that include non-ASCII characters.
     bool error;
-    int32_t realLength = Unicode::foldCase(data, length, m_data, m_length, &error);
+    int32_t realLength = Unicode::foldCase(data, length, m_data16, m_length, &error);
     if (!error && realLength == length)
         return newImpl.release();
     newImpl = createUninitialized(realLength, data);
-    Unicode::foldCase(data, realLength, m_data, m_length, &error);
+    Unicode::foldCase(data, realLength, m_data16, m_length, &error);
     if (error)
         return this;
     return newImpl.release();
@@ -309,7 +457,7 @@ inline PassRefPtr<StringImpl> StringImpl::stripMatchedCharacters(UCharPredicate
     unsigned end = m_length - 1;
     
     // skip white space from start
-    while (start <= end && predicate(m_data[start]))
+    while (start <= end && predicate(is8Bit() ? m_data8[start] : m_data16[start]))
         start++;
     
     // only white space
@@ -317,12 +465,14 @@ inline PassRefPtr<StringImpl> StringImpl::stripMatchedCharacters(UCharPredicate
         return empty();
 
     // skip white space from end
-    while (end && predicate(m_data[end]))
+    while (end && predicate(is8Bit() ? m_data8[end] : m_data16[end]))
         end--;
 
     if (!start && end == m_length - 1)
         return this;
-    return create(m_data + start, end + 1 - start);
+    if (is8Bit())
+        return create(m_data8 + start, end + 1 - start);
+    return create(m_data16 + start, end + 1 - start);
 }
 
 class UCharPredicate {
@@ -356,9 +506,10 @@ PassRefPtr<StringImpl> StringImpl::stripWhiteSpace(IsWhiteSpaceFunctionPtr isWhi
     return stripMatchedCharacters(UCharPredicate(isWhiteSpace));
 }
 
+// FIXME: Add 8-bit path. Likely requires templatized StringBuffer class
 PassRefPtr<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr findMatch)
 {
-    const UChar* from = m_data;
+    const UChar* from = characters();
     const UChar* fromend = from + m_length;
 
     // Assume the common case will not remove any characters
@@ -369,10 +520,10 @@ PassRefPtr<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr fi
 
     StringBuffer data(m_length);
     UChar* to = data.characters();
-    unsigned outc = from - m_data;
+    unsigned outc = from - characters16();
 
     if (outc)
-        memcpy(to, m_data, outc * sizeof(UChar));
+        memcpy(to, characters16(), outc * sizeof(UChar));
 
     while (true) {
         while (from != fromend && findMatch(*from))
@@ -388,12 +539,13 @@ PassRefPtr<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr fi
     return adopt(data);
 }
 
+// FIXME: Add 8-bit path. Likely requires templatized StringBuffer class
 template <class UCharPredicate>
 inline PassRefPtr<StringImpl> StringImpl::simplifyMatchedCharactersToSpace(UCharPredicate predicate)
 {
     StringBuffer data(m_length);
 
-    const UChar* from = m_data;
+    const UChar* from = characters16();
     const UChar* fromend = from + m_length;
     int outc = 0;
     bool changedToSpace = false;
@@ -437,65 +589,67 @@ PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace(IsWhiteSpaceFunctionPtr is
 
 int StringImpl::toIntStrict(bool* ok, int base)
 {
-    return charactersToIntStrict(m_data, m_length, ok, base);
+    return charactersToIntStrict(characters16(), m_length, ok, base);
 }
 
 unsigned StringImpl::toUIntStrict(bool* ok, int base)
 {
-    return charactersToUIntStrict(m_data, m_length, ok, base);
+    return charactersToUIntStrict(characters16(), m_length, ok, base);
 }
 
 int64_t StringImpl::toInt64Strict(bool* ok, int base)
 {
-    return charactersToInt64Strict(m_data, m_length, ok, base);
+    return charactersToInt64Strict(characters16(), m_length, ok, base);
+
 }
 
 uint64_t StringImpl::toUInt64Strict(bool* ok, int base)
 {
-    return charactersToUInt64Strict(m_data, m_length, ok, base);
+    return charactersToUInt64Strict(characters16(), m_length, ok, base);
 }
 
 intptr_t StringImpl::toIntPtrStrict(bool* ok, int base)
 {
-    return charactersToIntPtrStrict(m_data, m_length, ok, base);
+    return charactersToIntPtrStrict(characters16(), m_length, ok, base);
 }
 
 int StringImpl::toInt(bool* ok)
 {
-    return charactersToInt(m_data, m_length, ok);
+    return charactersToInt(characters16(), m_length, ok);
 }
 
 unsigned StringImpl::toUInt(bool* ok)
 {
-    return charactersToUInt(m_data, m_length, ok);
+    return charactersToUInt(characters16(), m_length, ok);
 }
 
 int64_t StringImpl::toInt64(bool* ok)
 {
-    return charactersToInt64(m_data, m_length, ok);
+    return charactersToInt64(characters16(), m_length, ok);
 }
 
 uint64_t StringImpl::toUInt64(bool* ok)
 {
-    return charactersToUInt64(m_data, m_length, ok);
+    return charactersToUInt64(characters16(), m_length, ok);
 }
 
 intptr_t StringImpl::toIntPtr(bool* ok)
 {
-    return charactersToIntPtr(m_data, m_length, ok);
+    return charactersToIntPtr(characters16(), m_length, ok);
+
 }
 
 double StringImpl::toDouble(bool* ok, bool* didReadNumber)
 {
-    return charactersToDouble(m_data, m_length, ok, didReadNumber);
+    return charactersToDouble(characters16(), m_length, ok, didReadNumber);
 }
 
 float StringImpl::toFloat(bool* ok, bool* didReadNumber)
 {
-    return charactersToFloat(m_data, m_length, ok, didReadNumber);
+    return charactersToFloat(characters16(), m_length, ok, didReadNumber);
 }
 
-static bool equal(const UChar* a, const char* b, int length)
+static bool equal(const UChar* a, const LChar* b, int length)
 {
     ASSERT(length >= 0);
     while (length--) {
@@ -506,7 +660,7 @@ static bool equal(const UChar* a, const char* b, int length)
     return true;
 }
 
-bool equalIgnoringCase(const UChar* a, const char* b, unsigned length)
+bool equalIgnoringCase(const UChar* a, const LChar* b, unsigned length)
 {
     while (length--) {
         unsigned char bc = *b++;
@@ -547,20 +701,20 @@ int codePointCompare(const StringImpl* s1, const StringImpl* s2)
 
 size_t StringImpl::find(UChar c, unsigned start)
 {
-    return WTF::find(m_data, m_length, c, start);
+    return WTF::find(characters16(), m_length, c, start);
 }
 
 size_t StringImpl::find(CharacterMatchFunctionPtr matchFunction, unsigned start)
 {
-    return WTF::find(m_data, m_length, matchFunction, start);
+    return WTF::find(characters16(), m_length, matchFunction, start);
 }
 
-size_t StringImpl::find(const char* matchString, unsigned index)
+size_t StringImpl::find(const LChar* matchString, unsigned index)
 {
     // Check for null or empty string to match against
     if (!matchString)
         return notFound;
-    size_t matchStringLength = strlen(matchString);
+    size_t matchStringLength = strlen(reinterpret_cast<const char*>(matchString));
     if (matchStringLength > numeric_limits<unsigned>::max())
         CRASH();
     unsigned matchLength = matchStringLength;
@@ -569,7 +723,7 @@ size_t StringImpl::find(const char* matchString, unsigned index)
 
     // Optimization 1: fast case for strings of length 1.
     if (matchLength == 1)
-        return WTF::find(characters(), length(), *(const unsigned char*)matchString, index);
+        return WTF::find(characters16(), length(), *matchString, index);
 
     // Check index & matchLength are in range.
     if (index > length())
@@ -581,7 +735,6 @@ size_t StringImpl::find(const char* matchString, unsigned index)
     unsigned delta = searchLength - matchLength;
 
     const UChar* searchCharacters = characters() + index;
-    const unsigned char* matchCharacters = (const unsigned char*)matchString;
 
     // Optimization 2: keep a running hash of the strings,
     // only call memcmp if the hashes match.
@@ -589,7 +742,7 @@ size_t StringImpl::find(const char* matchString, unsigned index)
     unsigned matchHash = 0;
     for (unsigned i = 0; i < matchLength; ++i) {
         searchHash += searchCharacters[i];
-        matchHash += matchCharacters[i];
+        matchHash += matchString[i];
     }
 
     unsigned i = 0;
@@ -604,12 +757,12 @@ size_t StringImpl::find(const char* matchString, unsigned index)
     return index + i;
 }
 
-size_t StringImpl::findIgnoringCase(const char* matchString, unsigned index)
+size_t StringImpl::findIgnoringCase(const LChar* matchString, unsigned index)
 {
     // Check for null or empty string to match against
     if (!matchString)
         return notFound;
-    size_t matchStringLength = strlen(matchString);
+    size_t matchStringLength = strlen(reinterpret_cast<const char*>(matchString));
     if (matchStringLength > numeric_limits<unsigned>::max())
         CRASH();
     unsigned matchLength = matchStringLength;
@@ -648,7 +801,7 @@ size_t StringImpl::find(StringImpl* matchString, unsigned index)
 
     // Optimization 1: fast case for strings of length 1.
     if (matchLength == 1)
-        return WTF::find(characters(), length(), matchString->characters()[0], index);
+        return WTF::find(characters16(), length(), matchString->characters16()[0], index);
 
     // Check index & matchLength are in range.
     if (index > length())
@@ -716,7 +869,7 @@ size_t StringImpl::findIgnoringCase(StringImpl* matchString, unsigned index)
 
 size_t StringImpl::reverseFind(UChar c, unsigned index)
 {
-    return WTF::reverseFind(m_data, m_length, c, index);
+    return WTF::reverseFind(characters16(), m_length, c, index);
 }
 
 size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index)
@@ -730,7 +883,7 @@ size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index)
 
     // Optimization 1: fast case for strings of length 1.
     if (matchLength == 1)
-        return WTF::reverseFind(characters(), length(), matchString->characters()[0], index);
+        return WTF::reverseFind(characters16(), length(), matchString->characters()[0], index);
 
     // Check index & matchLength are in range.
     if (matchLength > length())
@@ -803,17 +956,55 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
     if (oldC == newC)
         return this;
     unsigned i;
-    for (i = 0; i != m_length; ++i)
-        if (m_data[i] == oldC)
+    for (i = 0; i != m_length; ++i) {
+        UChar c = is8Bit() ? m_data8[i] : m_data16[i];
+        if (c == oldC)
             break;
+    }
     if (i == m_length)
         return this;
 
+    if (is8Bit()) {
+        if (oldC > 0xff)
+            // Looking for a 16 bit char in an 8 bit string, we're done.
+            return this;
+
+        if (newC <= 0xff) {
+            LChar* data;
+            LChar oldChar = static_cast<LChar>(oldC);
+            LChar newChar = static_cast<LChar>(newC);
+
+            RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+
+            for (i = 0; i != m_length; ++i) {
+                char ch = m_data8[i];
+                if (ch == oldChar)
+                    ch = newChar;
+                data[i] = ch;
+            }
+            return newImpl.release();
+        }
+
+        // There is the possibility we need to up convert from 8 to 16 bit,
+        // create a 16 bit string for the result.
+        UChar* data;
+        RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
+
+        for (i = 0; i != m_length; ++i) {
+            UChar ch = m_data8[i];
+            if (ch == oldC)
+                ch = newC;
+            data[i] = ch;
+        }
+
+        return newImpl.release();
+    }
+
     UChar* data;
     RefPtr<StringImpl> newImpl = createUninitialized(m_length, data);
 
     for (i = 0; i != m_length; ++i) {
-        UChar ch = m_data[i];
+        UChar ch = m_data16[i];
         if (ch == oldC)
             ch = newC;
         data[i] = ch;
@@ -828,18 +1019,43 @@ PassRefPtr<StringImpl> StringImpl::replace(unsigned position, unsigned lengthToR
     unsigned lengthToInsert = str ? str->length() : 0;
     if (!lengthToReplace && !lengthToInsert)
         return this;
-    UChar* data;
 
     if ((length() - lengthToReplace) >= (numeric_limits<unsigned>::max() - lengthToInsert))
         CRASH();
 
+    if (is8Bit() && (!str || str->is8Bit())) {
+        LChar* data;
+        RefPtr<StringImpl> newImpl =
+        createUninitialized(length() - lengthToReplace + lengthToInsert, data);
+        memcpy(data, m_data8, position * sizeof(LChar));
+        if (str)
+            memcpy(data + position, str->m_data8, lengthToInsert * sizeof(LChar));
+        memcpy(data + position + lengthToInsert, m_data8 + position + lengthToReplace,
+               (length() - position - lengthToReplace) * sizeof(LChar));
+        return newImpl.release();
+    }
+    UChar* data;
     RefPtr<StringImpl> newImpl =
         createUninitialized(length() - lengthToReplace + lengthToInsert, data);
-    memcpy(data, characters(), position * sizeof(UChar));
-    if (str)
-        memcpy(data + position, str->characters(), lengthToInsert * sizeof(UChar));
-    memcpy(data + position + lengthToInsert, characters() + position + lengthToReplace,
-        (length() - position - lengthToReplace) * sizeof(UChar));
+    if (is8Bit())
+        for (unsigned i = 0; i < position; i++)
+            data[i] = m_data8[i];
+    else
+        memcpy(data, m_data16, position * sizeof(UChar));
+    if (str) {
+        if (str->is8Bit())
+            for (unsigned i = 0; i < lengthToInsert; i++)
+                data[i + position] = str->m_data8[i];
+        else
+            memcpy(data + position, str->m_data16, lengthToInsert * sizeof(UChar));
+    }
+    if (is8Bit()) {
+        for (unsigned i = 0; i < length() - position - lengthToReplace; i++)
+            data[i + position + lengthToInsert] = m_data8[i + position + lengthToReplace];
+    } else {
+        memcpy(data + position + lengthToInsert, characters() + position + lengthToReplace,
+            (length() - position - lengthToReplace) * sizeof(UChar));
+    }
     return newImpl.release();
 }
 
@@ -852,13 +1068,13 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen
     size_t srcSegmentStart = 0;
     unsigned matchCount = 0;
     
-    // Count the matches
+    // Count the matches.
     while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) {
         ++matchCount;
         ++srcSegmentStart;
     }
     
-    // If we have 0 matches, we don't have to do any more work
+    // If we have 0 matches then we don't have to do any more work to do.
     if (!matchCount)
         return this;
     
@@ -872,26 +1088,76 @@ PassRefPtr<StringImpl> StringImpl::replace(UChar pattern, StringImpl* replacemen
 
     newSize += replaceSize;
 
-    UChar* data;
-    RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
-
-    // Construct the new data
+    // Construct the new data.
     size_t srcSegmentEnd;
     unsigned srcSegmentLength;
     srcSegmentStart = 0;
     unsigned dstOffset = 0;
+    bool srcIs8Bit = is8Bit();
+    bool replacementIs8Bit = replacement->is8Bit();
     
+    // There are 4 cases:
+    // 1. This and replacement are both 8 bit.
+    // 2. This and replacement are both 16 bit.
+    // 3. This is 8 bit and replacement is 16 bit.
+    // 4. This is 16 bit and replacement is 8 bit.
+    if (srcIs8Bit && replacementIs8Bit) {
+        // Case 1
+        LChar* data;
+        RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+
+        while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+            srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+            memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+            dstOffset += srcSegmentLength;
+            memcpy(data + dstOffset, replacement->m_data8, repStrLength * sizeof(LChar));
+            dstOffset += repStrLength;
+            srcSegmentStart = srcSegmentEnd + 1;
+        }
+
+        srcSegmentLength = m_length - srcSegmentStart;
+        memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+
+        ASSERT(dstOffset + srcSegmentLength == newImpl->length());
+
+        return newImpl.release();
+    }
+
+    UChar* data;
+    RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+
     while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
         srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-        memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        if (srcIs8Bit) {
+            // Case 3.
+            for (unsigned i = 0; i < srcSegmentLength; i++)
+                data[i + dstOffset] = m_data8[i + srcSegmentStart];
+        } else {
+            // Cases 2 & 4.
+            memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        }
         dstOffset += srcSegmentLength;
-        memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar));
+        if (replacementIs8Bit) {
+            // Case 4.
+            for (unsigned i = 0; i < repStrLength; i++)
+                data[i + dstOffset] = replacement->m_data8[i];
+        } else {
+            // Cases 2 & 3.
+            memcpy(data + dstOffset, replacement->m_data16, repStrLength * sizeof(UChar));
+        }
         dstOffset += repStrLength;
         srcSegmentStart = srcSegmentEnd + 1;
     }
 
     srcSegmentLength = m_length - srcSegmentStart;
-    memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    if (srcIs8Bit) {
+        // Case 3.
+        for (unsigned i = 0; i < srcSegmentLength; i++)
+            data[i + dstOffset] = m_data8[i + srcSegmentStart];
+    } else {
+        // Cases 2 & 4.
+        memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    }
 
     ASSERT(dstOffset + srcSegmentLength == newImpl->length());
 
@@ -911,7 +1177,7 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl
     size_t srcSegmentStart = 0;
     unsigned matchCount = 0;
     
-    // Count the matches
+    // Count the matches.
     while ((srcSegmentStart = find(pattern, srcSegmentStart)) != notFound) {
         ++matchCount;
         srcSegmentStart += patternLength;
@@ -930,26 +1196,75 @@ PassRefPtr<StringImpl> StringImpl::replace(StringImpl* pattern, StringImpl* repl
 
     newSize += matchCount * repStrLength;
 
-    UChar* data;
-    RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
     
     // Construct the new data
     size_t srcSegmentEnd;
     unsigned srcSegmentLength;
     srcSegmentStart = 0;
     unsigned dstOffset = 0;
+    bool srcIs8Bit = is8Bit();
+    bool replacementIs8Bit = replacement->is8Bit();
     
+    // There are 4 cases:
+    // 1. This and replacement are both 8 bit.
+    // 2. This and replacement are both 16 bit.
+    // 3. This is 8 bit and replacement is 16 bit.
+    // 4. This is 16 bit and replacement is 8 bit.
+    if (srcIs8Bit && replacementIs8Bit) {
+        // Case 1
+        LChar* data;
+        RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
+        while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
+            srcSegmentLength = srcSegmentEnd - srcSegmentStart;
+            memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+            dstOffset += srcSegmentLength;
+            memcpy(data + dstOffset, replacement->m_data8, repStrLength * sizeof(LChar));
+            dstOffset += repStrLength;
+            srcSegmentStart = srcSegmentEnd + patternLength;
+        }
+
+        srcSegmentLength = m_length - srcSegmentStart;
+        memcpy(data + dstOffset, m_data8 + srcSegmentStart, srcSegmentLength * sizeof(LChar));
+
+        ASSERT(dstOffset + srcSegmentLength == newImpl->length());
+
+        return newImpl.release();
+    }
+
+    UChar* data;
+    RefPtr<StringImpl> newImpl = createUninitialized(newSize, data);
     while ((srcSegmentEnd = find(pattern, srcSegmentStart)) != notFound) {
         srcSegmentLength = srcSegmentEnd - srcSegmentStart;
-        memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        if (srcIs8Bit) {
+            // Case 3.
+            for (unsigned i = 0; i < srcSegmentLength; i++)
+                data[i + dstOffset] = m_data8[i + srcSegmentStart];
+        } else {
+            // Case 2 & 4.
+            memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+        }
         dstOffset += srcSegmentLength;
-        memcpy(data + dstOffset, replacement->m_data, repStrLength * sizeof(UChar));
+        if (replacementIs8Bit) {
+            // Cases 2 & 3.
+            for (unsigned i = 0; i < repStrLength; i++)
+                data[i + dstOffset] = replacement->m_data8[i];
+        } else {
+            // Case 4
+            memcpy(data + dstOffset, replacement->m_data16, repStrLength * sizeof(UChar));
+        }
         dstOffset += repStrLength;
         srcSegmentStart = srcSegmentEnd + patternLength;
     }
 
     srcSegmentLength = m_length - srcSegmentStart;
-    memcpy(data + dstOffset, m_data + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    if (srcIs8Bit) {
+        // Case 3.
+        for (unsigned i = 0; i < srcSegmentLength; i++)
+            data[i + dstOffset] = m_data8[i + srcSegmentStart];
+    } else {
+        // Cases 2 & 4.
+        memcpy(data + dstOffset, m_data16 + srcSegmentStart, srcSegmentLength * sizeof(UChar));
+    }
 
     ASSERT(dstOffset + srcSegmentLength == newImpl->length());
 
@@ -961,7 +1276,46 @@ bool equal(const StringImpl* a, const StringImpl* b)
     return StringHash::equal(a, b);
 }
 
-bool equal(const StringImpl* a, const char* b)
+bool equal(const StringImpl* a, const LChar* b, unsigned length)
+{
+    if (!a)
+        return !b;
+    if (!b)
+        return !a;
+
+    if (length != a->length())
+        return false;
+
+    if (a->is8Bit()) {
+        const LChar* aChars = a->characters8();
+
+        for (unsigned i = 0; i != length; ++i) {
+            unsigned char bc = b[i];
+            unsigned char ac = aChars[i];
+            if (!bc)
+                return false;
+            if (ac != bc)
+                return false;
+        }
+
+        return true;
+    }
+
+    const UChar* aChars = a->characters16();
+
+    for (unsigned i = 0; i != length; ++i) {
+        UChar bc = b[i];
+        UChar ac = aChars[i];
+        if (!bc)
+            return false;
+        if (ac != bc)
+            return false;
+    }
+
+    return true;
+}
+
+bool equal(const StringImpl* a, const LChar* b)
 {
     if (!a)
         return !b;
@@ -969,12 +1323,27 @@ bool equal(const StringImpl* a, const char* b)
         return !a;
 
     unsigned length = a->length();
-    const UChar* as = a->characters();
+
+    if (a->is8Bit()) {
+        const LChar* aPtr = a->characters8();
+        for (unsigned i = 0; i != length; ++i) {
+            unsigned char bc = b[i];
+            unsigned char ac = aPtr[i];
+            if (!bc)
+                return false;
+            if (ac != bc)
+                return false;
+        }
+
+        return !b[length];
+    }
+
+    const UChar* aPtr = a->characters16();
     for (unsigned i = 0; i != length; ++i) {
         unsigned char bc = b[i];
         if (!bc)
             return false;
-        if (as[i] != bc)
+        if (aPtr[i] != bc)
             return false;
     }
 
@@ -999,20 +1368,28 @@ bool equal(const StringImpl* a, const UChar* b, unsigned length)
             return false;
     return true;
 #else
-    /* Do it 4-bytes-at-a-time on architectures where it's safe */
-    
-    const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a->characters());
+    if (a->is8Bit()) {
+        const LChar* as = a->characters8();
+        for (unsigned i = 0; i != length; ++i)
+            if (as[i] != b[i])
+                return false;
+        return true;
+    }
+
+    // Do comparison 4-bytes-at-a-time on architectures where it's safe.
+
+    const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a->characters16());
     const uint32_t* bCharacters = reinterpret_cast<const uint32_t*>(b);
-    
+
     unsigned halfLength = length >> 1;
     for (unsigned i = 0; i != halfLength; ++i) {
         if (*aCharacters++ != *bCharacters++)
             return false;
     }
-    
+
     if (length & 1 &&  *reinterpret_cast<const uint16_t*>(aCharacters) != *reinterpret_cast<const uint16_t*>(bCharacters))
         return false;
-    
+
     return true;
 #endif
 }
@@ -1022,7 +1399,7 @@ bool equalIgnoringCase(StringImpl* a, StringImpl* b)
     return CaseFoldingHash::equal(a, b);
 }
 
-bool equalIgnoringCase(StringImpl* a, const char* b)
+bool equalIgnoringCase(StringImpl* a, const LChar* b)
 {
     if (!a)
         return !b;
@@ -1030,13 +1407,34 @@ bool equalIgnoringCase(StringImpl* a, const char* b)
         return !a;
 
     unsigned length = a->length();
-    const UChar* as = a->characters();
 
     // Do a faster loop for the case where all the characters are ASCII.
     UChar ored = 0;
     bool equal = true;
+    if (a->is8Bit()) {
+        const LChar* as = a->characters8();
+        for (unsigned i = 0; i != length; ++i) {
+            LChar bc = b[i];
+            if (!bc)
+                return false;
+            UChar ac = as[i];
+            ored |= ac;
+            equal = equal && (toASCIILower(ac) == toASCIILower(bc));
+        }
+        
+        // Do a slower implementation for cases that include non-ASCII characters.
+        if (ored & ~0x7F) {
+            equal = true;
+            for (unsigned i = 0; i != length; ++i)
+                equal = equal && (foldCase(as[i]) == foldCase(b[i]));
+        }
+        
+        return equal && !b[length];        
+    }
+
+    const UChar* as = a->characters16();
     for (unsigned i = 0; i != length; ++i) {
-        char bc = b[i];
+        LChar bc = b[i];
         if (!bc)
             return false;
         UChar ac = as[i];
@@ -1048,8 +1446,7 @@ bool equalIgnoringCase(StringImpl* a, const char* b)
     if (ored & ~0x7F) {
         equal = true;
         for (unsigned i = 0; i != length; ++i) {
-            unsigned char bc = b[i];
-            equal = equal && (foldCase(as[i]) == foldCase(bc));
+            equal = equal && (foldCase(as[i]) == foldCase(b[i]));
         }
     }
 
@@ -1071,7 +1468,7 @@ bool equalIgnoringNullity(StringImpl* a, StringImpl* b)
 WTF::Unicode::Direction StringImpl::defaultWritingDirection(bool* hasStrongDirectionality)
 {
     for (unsigned i = 0; i < m_length; ++i) {
-        WTF::Unicode::Direction charDirection = WTF::Unicode::direction(m_data[i]);
+        WTF::Unicode::Direction charDirection = WTF::Unicode::direction(is8Bit() ? m_data8[i] : m_data16[i]);
         if (charDirection == WTF::Unicode::LeftToRight) {
             if (hasStrongDirectionality)
                 *hasStrongDirectionality = true;
@@ -1090,6 +1487,7 @@ WTF::Unicode::Direction StringImpl::defaultWritingDirection(bool* hasStrongDirec
 
 PassRefPtr<StringImpl> StringImpl::adopt(StringBuffer& buffer)
 {
+    // FIXME: handle 8-bit StringBuffer when it exists.
     unsigned length = buffer.length();
     if (length == 0)
         return empty();
@@ -1100,13 +1498,21 @@ PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const Stri
 {
     // Use createUninitialized instead of 'new StringImpl' so that the string and its buffer
     // get allocated in a single memory block.
-    UChar* data;
     unsigned length = string.m_length;
     if (length >= numeric_limits<unsigned>::max())
         CRASH();
-    RefPtr<StringImpl> terminatedString = createUninitialized(length + 1, data);
-    memcpy(data, string.m_data, length * sizeof(UChar));
-    data[length] = 0;
+    RefPtr<StringImpl> terminatedString;
+    if (string.is8Bit()) {
+        LChar* data;
+        terminatedString = createUninitialized(length + 1, data);
+        memcpy(data, string.m_data8, length * sizeof(LChar));
+        data[length] = 0;
+    } else {
+        UChar* data;
+        terminatedString = createUninitialized(length + 1, data);
+        memcpy(data, string.m_data16, length * sizeof(UChar));
+        data[length] = 0;
+    }
     terminatedString->m_length--;
     terminatedString->m_hashAndFlags = (string.m_hashAndFlags & ~s_flagMask) | s_hashFlagHasTerminatingNullCharacter;
     return terminatedString.release();
index 0cf200b..38caf33 100644 (file)
@@ -44,6 +44,7 @@ typedef const struct __CFString * CFStringRef;
 // Landing the file moves in one patch, will follow on with patches to change the namespaces.
 namespace JSC {
 struct IdentifierCStringTranslator;
+struct IdentifierCharBufferTranslator;
 struct IdentifierUCharBufferTranslator;
 }
 
@@ -62,6 +63,7 @@ typedef bool (*IsWhiteSpaceFunctionPtr)(UChar);
 class StringImpl {
     WTF_MAKE_NONCOPYABLE(StringImpl); WTF_MAKE_FAST_ALLOCATED;
     friend struct JSC::IdentifierCStringTranslator;
+    friend struct JSC::IdentifierCharBufferTranslator;
     friend struct JSC::IdentifierUCharBufferTranslator;
     friend struct WTF::CStringTranslator;
     friend struct WTF::HashAndCharactersTranslator;
@@ -83,7 +85,7 @@ private:
     StringImpl(const UChar* characters, unsigned length, ConstructStaticStringTag)
         : m_refCount(s_refCountFlagIsStaticString)
         , m_length(length)
-        , m_data(characters)
+        , m_data16(characters)
         , m_buffer(0)
         , m_hashAndFlags(s_hashFlagIsIdentifier | BufferOwned)
     {
@@ -93,15 +95,45 @@ private:
         hash();
     }
 
-    // Create a normal string with internal storage (BufferInternal)
+    // Used to construct static strings, which have an special refCount that can never hit zero.
+    // This means that the static string will never be destroyed, which is important because
+    // static strings will be shared across threads & ref-counted in a non-threadsafe manner.
+    StringImpl(const LChar* characters, unsigned length, ConstructStaticStringTag)
+        : m_refCount(s_refCountFlagIsStaticString)
+        , m_length(length)
+        , m_data8(characters)
+        , m_buffer(0)
+        , m_hashAndFlags(s_hashFlag8BitBuffer | s_hashFlagIsIdentifier | BufferOwned)
+    {
+        // Ensure that the hash is computed so that AtomicStringHash can call existingHash()
+        // with impunity. The empty string is special because it is never entered into
+        // AtomicString's HashKey, but still needs to compare correctly.
+        hash();
+    }
+
+    // FIXME: there has to be a less hacky way to do this.
+    enum Force8Bit { Force8BitConstructor };
+    // Create a normal 8-bit string with internal storage (BufferInternal)
+    StringImpl(unsigned length, Force8Bit)
+        : m_refCount(s_refCountIncrement)
+        , m_length(length)
+        , m_data8(reinterpret_cast<const LChar*>(this + 1))
+        , m_buffer(0)
+        , m_hashAndFlags(s_hashFlag8BitBuffer | BufferInternal)
+    {
+        ASSERT(m_data8);
+        ASSERT(m_length);
+    }
+
+    // Create a normal 16-bit string with internal storage (BufferInternal)
     StringImpl(unsigned length)
         : m_refCount(s_refCountIncrement)
         , m_length(length)
-        , m_data(reinterpret_cast<const UChar*>(this + 1))
+        , m_data16(reinterpret_cast<const UChar*>(this + 1))
         , m_buffer(0)
         , m_hashAndFlags(BufferInternal)
     {
-        ASSERT(m_data);
+        ASSERT(m_data16);
         ASSERT(m_length);
     }
 
@@ -109,23 +141,38 @@ private:
     StringImpl(const UChar* characters, unsigned length)
         : m_refCount(s_refCountIncrement)
         , m_length(length)
-        , m_data(characters)
+        , m_data16(characters)
         , m_buffer(0)
         , m_hashAndFlags(BufferOwned)
     {
-        ASSERT(m_data);
+        ASSERT(m_data16);
+        ASSERT(m_length);
+    }
+
+    // Used to create new strings that are a substring of an existing 8-bit StringImpl (BufferSubstring)
+    StringImpl(const LChar* characters, unsigned length, PassRefPtr<StringImpl> base)
+        : m_refCount(s_refCountIncrement)
+        , m_length(length)
+        , m_data8(characters)
+        , m_substringBuffer(base.leakRef())
+        , m_hashAndFlags(s_hashFlag8BitBuffer | BufferSubstring)
+    {
+        ASSERT(is8Bit());
+        ASSERT(m_data8);
         ASSERT(m_length);
+        ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
     }
 
-    // Used to create new strings that are a substring of an existing StringImpl (BufferSubstring)
+    // Used to create new strings that are a substring of an existing 16-bit StringImpl (BufferSubstring)
     StringImpl(const UChar* characters, unsigned length, PassRefPtr<StringImpl> base)
         : m_refCount(s_refCountIncrement)
         , m_length(length)
-        , m_data(characters)
+        , m_data16(characters)
         , m_substringBuffer(base.leakRef())
         , m_hashAndFlags(BufferSubstring)
     {
-        ASSERT(m_data);
+        ASSERT(!is8Bit());
+        ASSERT(m_data16);
         ASSERT(m_length);
         ASSERT(m_substringBuffer->bufferOwnership() != BufferSubstring);
     }
@@ -134,8 +181,24 @@ public:
     ~StringImpl();
 
     static PassRefPtr<StringImpl> create(const UChar*, unsigned length);
-    static PassRefPtr<StringImpl> create(const char*, unsigned length);
-    static PassRefPtr<StringImpl> create(const char*);
+    static PassRefPtr<StringImpl> create(const LChar*, unsigned length);
+    ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s, unsigned length) { return create(s, length); };
+    static PassRefPtr<StringImpl> create(const LChar*);
+    ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s) { return create(reinterpret_cast<const LChar*>(s)); };
+
+    static ALWAYS_INLINE PassRefPtr<StringImpl> create8(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length)
+    {
+        ASSERT(rep);
+        ASSERT(length <= rep->length());
+
+        if (!length)
+            return empty();
+
+        ASSERT(rep->is8Bit());
+        StringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get();
+        return adoptRef(new StringImpl(rep->m_data8 + offset, length, ownerRep));
+    }
+
     static ALWAYS_INLINE PassRefPtr<StringImpl> create(PassRefPtr<StringImpl> rep, unsigned offset, unsigned length)
     {
         ASSERT(rep);
@@ -145,27 +208,34 @@ public:
             return empty();
 
         StringImpl* ownerRep = (rep->bufferOwnership() == BufferSubstring) ? rep->m_substringBuffer : rep.get();
-        return adoptRef(new StringImpl(rep->m_data + offset, length, ownerRep));
+        if (rep->is8Bit())
+            return adoptRef(new StringImpl(rep->m_data8 + offset, length, ownerRep));
+        return adoptRef(new StringImpl(rep->m_data16 + offset, length, ownerRep));
     }
 
+    static PassRefPtr<StringImpl> createUninitialized(unsigned length, LChar*& data);
     static PassRefPtr<StringImpl> createUninitialized(unsigned length, UChar*& data);
-    static ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, UChar*& output)
+    template <typename T> static ALWAYS_INLINE PassRefPtr<StringImpl> tryCreateUninitialized(unsigned length, T*& output)
     {
         if (!length) {
             output = 0;
             return empty();
         }
 
-        if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(UChar))) {
+        if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(T))) {
             output = 0;
             return 0;
         }
         StringImpl* resultImpl;
-        if (!tryFastMalloc(sizeof(UChar) * length + sizeof(StringImpl)).getValue(resultImpl)) {
+        if (!tryFastMalloc(sizeof(T) * length + sizeof(StringImpl)).getValue(resultImpl)) {
             output = 0;
             return 0;
         }
-        output = reinterpret_cast<UChar*>(resultImpl + 1);
+        output = reinterpret_cast<T*>(resultImpl + 1);
+
+        if (sizeof(T) == sizeof(char))
+            return adoptRef(new(resultImpl) StringImpl(length, Force8BitConstructor));
+
         return adoptRef(new(resultImpl) StringImpl(length));
     }
 
@@ -174,7 +244,9 @@ public:
     // the originalString can't be used after this function.
     static PassRefPtr<StringImpl> reallocate(PassRefPtr<StringImpl> originalString, unsigned length, UChar*& data);
 
-    static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data); }
+    static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); }
+    static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
+    static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
     static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&);
 
     template<size_t inlineCapacity>
@@ -191,7 +263,18 @@ public:
     static PassRefPtr<StringImpl> adopt(StringBuffer&);
 
     unsigned length() const { return m_length; }
-    const UChar* characters() const { return m_data; }
+    bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; }
+
+    // FIXME: Remove all unnecessary usages of characters()
+    ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); ASSERT_NOT_REACHED(); return m_data8; }
+    ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return m_data16; }
+    ALWAYS_INLINE const UChar* characters() const
+    {
+        if (!is8Bit())
+            return m_data16;
+
+        return getData16SlowCase();
+    }
 
     size_t cost()
     {
@@ -206,6 +289,7 @@ public:
         return m_length;
     }
 
+    bool has16BitShadow() const { return m_hashAndFlags & s_hashFlagHas16BitShadow; }
     bool isIdentifier() const { return m_hashAndFlags & s_hashFlagIsIdentifier; }
     void setIsIdentifier(bool isIdentifier)
     {
@@ -235,7 +319,8 @@ private:
     void setHash(unsigned hash) const
     {
         ASSERT(!hasHash());
-        ASSERT(hash == StringHasher::computeHash(m_data, m_length)); // Multiple clients assume that StringHasher is the canonical string hash function.
+        // Multiple clients assume that StringHasher is the canonical string hash function.
+        ASSERT(hash == (is8Bit() ? StringHasher::computeHash(m_data8, m_length) : StringHasher::computeHash(m_data16, m_length)));
         ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // Verify that enough high bits are empty.
         
         hash <<= s_flagCount;
@@ -264,8 +349,12 @@ public:
 
     unsigned hash() const
     {
-        if (!hasHash())
-            setHash(StringHasher::computeHash(m_data, m_length));
+        if (!hasHash()) {
+            if (is8Bit())
+                setHash(StringHasher::computeHash(m_data8, m_length));
+            else
+                setHash(StringHasher::computeHash(m_data16, m_length));
+        }
         return existingHash();
     }
 
@@ -291,13 +380,32 @@ public:
 
     static StringImpl* empty();
 
-    static void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
+    // FIXME: Does this really belong in StringImpl?
+    template <typename T> static void copyChars(T* destination, const T* source, unsigned numCharacters)
     {
+        if (numCharacters == 1) {
+            *destination = *source;
+            return;
+        }
+
         if (numCharacters <= s_copyCharsInlineCutOff) {
-            for (unsigned i = 0; i < numCharacters; ++i)
+            unsigned i = 0;
+#if (CPU(X86) || CPU(X86_64))
+            const unsigned charsPerInt = sizeof(uint32_t) / sizeof(T);
+
+            if (numCharacters > charsPerInt) {
+                unsigned stopCount = numCharacters & ~(charsPerInt - 1);
+
+                const uint32_t* srcCharacters = reinterpret_cast<const uint32_t*>(source);
+                uint32_t* destCharacters = reinterpret_cast<uint32_t*>(destination);
+                for (unsigned j = 0; i < stopCount; i += charsPerInt, ++j)
+                    destCharacters[j] = srcCharacters[j];
+            }
+#endif
+            for (; i < numCharacters; ++i)
                 destination[i] = source[i];
         } else
-            memcpy(destination, source, numCharacters * sizeof(UChar));
+            memcpy(destination, source, numCharacters * sizeof(T));
     }
 
     // Some string features, like refcounting and the atomicity flag, are not
@@ -307,7 +415,13 @@ public:
 
     PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX);
 
-    UChar operator[](unsigned i) { ASSERT(i < m_length); return m_data[i]; }
+    UChar operator[](unsigned i) const
+    {
+        ASSERT(i < m_length);
+        if (is8Bit())
+            return m_data8[i];
+        return m_data16[i];
+    }
     UChar32 characterStartingAt(unsigned);
 
     bool containsOnlyWhitespace();
@@ -331,6 +445,7 @@ public:
     PassRefPtr<StringImpl> upper();
 
     PassRefPtr<StringImpl> fill(UChar);
+    // FIXME: Do we need fill(char) or can we just do the right thing if UChar is ASCII?
     PassRefPtr<StringImpl> foldCase();
 
     PassRefPtr<StringImpl> stripWhiteSpace();
@@ -340,11 +455,14 @@ public:
 
     PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr);
 
+    // FIXME: Do we need char version, or is it okay to just pass in an ASCII char for 8-bit? Same for reverseFind, replace
     size_t find(UChar, unsigned index = 0);
     size_t find(CharacterMatchFunctionPtr, unsigned index = 0);
-    size_t find(const char*, unsigned index = 0);
+    size_t find(const LChar*, unsigned index = 0);
+    ALWAYS_INLINE size_t find(const char* s, unsigned index = 0) { return find(reinterpret_cast<const LChar*>(s), index); };
     size_t find(StringImpl*, unsigned index = 0);
-    size_t findIgnoringCase(const char*, unsigned index = 0);
+    size_t findIgnoringCase(const LChar*, unsigned index = 0);
+    ALWAYS_INLINE size_t findIgnoringCase(const char* s, unsigned index = 0) { return findIgnoringCase(reinterpret_cast<const LChar*>(s), index); };
     size_t findIgnoringCase(StringImpl*, unsigned index = 0);
 
     size_t reverseFind(UChar, unsigned index = UINT_MAX);
@@ -376,6 +494,7 @@ private:
     bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; }
     template <class UCharPredicate> PassRefPtr<StringImpl> stripMatchedCharacters(UCharPredicate);
     template <class UCharPredicate> PassRefPtr<StringImpl> simplifyMatchedCharactersToSpace(UCharPredicate);
+    NEVER_INLINE const UChar* getData16SlowCase() const;
 
     // The bottom bit in the ref count indicates a static (immortal) string.
     static const unsigned s_refCountFlagIsStaticString = 0x1;
@@ -386,6 +505,8 @@ private:
     static const unsigned s_flagMask = (1u << s_flagCount) - 1;
     COMPILE_ASSERT(s_flagCount == StringHasher::flagCount, StringHasher_reserves_enough_bits_for_StringImpl_flags);
 
+    static const unsigned s_hashFlagHas16BitShadow = 1u << 7;
+    static const unsigned s_hashFlag8BitBuffer = 1u << 6;
     static const unsigned s_hashFlagHasTerminatingNullCharacter = 1u << 5;
     static const unsigned s_hashFlagIsAtomic = 1u << 4;
     static const unsigned s_hashFlagDidReportCost = 1u << 3;
@@ -394,24 +515,33 @@ private:
 
     unsigned m_refCount;
     unsigned m_length;
-    const UChar* m_data;
+    union {
+        const LChar* m_data8;
+        const UChar* m_data16;
+    };
     union {
         void* m_buffer;
         StringImpl* m_substringBuffer;
+        mutable UChar* m_copyData16;
     };
     mutable unsigned m_hashAndFlags;
 };
 
 bool equal(const StringImpl*, const StringImpl*);
-bool equal(const StringImpl*, const char*);
-inline bool equal(const char* a, StringImpl* b) { return equal(b, a); }
+bool equal(const StringImpl*, const LChar*);
+inline bool equal(const StringImpl* a, const char* b) { return equal(a, reinterpret_cast<const LChar*>(b)); }
+bool equal(const StringImpl*, const LChar*, unsigned);
+inline bool equal(const LChar* a, StringImpl* b) { return equal(b, a); }
+inline bool equal(const char* a, StringImpl* b) { return equal(b, reinterpret_cast<const LChar*>(a)); }
 bool equal(const StringImpl*, const UChar*, unsigned);
 
 bool equalIgnoringCase(StringImpl*, StringImpl*);
-bool equalIgnoringCase(StringImpl*, const char*);
-inline bool equalIgnoringCase(const char* a, StringImpl* b) { return equalIgnoringCase(b, a); }
-bool equalIgnoringCase(const UChar* a, const char* b, unsigned length);
-inline bool equalIgnoringCase(const char* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, a, length); }
+bool equalIgnoringCase(StringImpl*, const LChar*);
+inline bool equalIgnoringCase(const LChar* a, StringImpl* b) { return equalIgnoringCase(b, a); }
+bool equalIgnoringCase(const UChar*, const LChar*, unsigned);
+inline bool equalIgnoringCase(const UChar* a, const char* b, unsigned length) { return equalIgnoringCase(a, reinterpret_cast<const LChar*>(b), length); }
+inline bool equalIgnoringCase(const LChar* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, a, length); }
+inline bool equalIgnoringCase(const char* a, const UChar* b, unsigned length) { return equalIgnoringCase(b, reinterpret_cast<const LChar*>(a), length); }
 
 bool equalIgnoringNullity(StringImpl*, StringImpl*);
 
@@ -436,7 +566,9 @@ static inline bool isSpaceOrNewline(UChar c)
 
 inline PassRefPtr<StringImpl> StringImpl::isolatedCopy() const
 {
-    return create(m_data, m_length);
+    if (is8Bit())
+        return create(m_data8, m_length);
+    return create(m_data16, m_length);
 }
 
 struct StringHash;
index ba72a88..77385b1 100644 (file)
@@ -61,17 +61,27 @@ String::String(const UChar* str)
 }
 
 // Construct a string with latin1 data.
-String::String(const char* characters, unsigned length)
+String::String(const LChar* characters, unsigned length)
     : m_impl(characters ? StringImpl::create(characters, length) : 0)
 {
 }
 
+String::String(const char* characters, unsigned length)
+    : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters), length) : 0)
+{
+}
+
 // Construct a string with latin1 data, from a null-terminated source.
-String::String(const char* characters)
+String::String(const LChar* characters)
     : m_impl(characters ? StringImpl::create(characters) : 0)
 {
 }
 
+String::String(const char* characters)
+    : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters)) : 0)
+{
+}
+
 void String::append(const String& str)
 {
     if (str.isEmpty())
@@ -95,7 +105,7 @@ void String::append(const String& str)
     }
 }
 
-void String::append(char c)
+void String::append(LChar c)
 {
     // FIXME: This is extremely inefficient. So much so that we might want to take this
     // out of String's API. We can make it better by optimizing the case where exactly
@@ -338,7 +348,7 @@ String String::format(const char *format, ...)
     va_end(args);
 
     QByteArray ba = buffer.toUtf8();
-    return StringImpl::create(ba.constData(), ba.length());
+    return StringImpl::create(reinterpret_cast<const LChar*>(ba.constData()), ba.length());
 
 #elif OS(WINCE)
     va_list args;
@@ -355,7 +365,7 @@ String String::format(const char *format, ...)
         if (written == 0)
             return String("");
         if (written > 0)
-            return StringImpl::create(buffer.data(), written);
+            return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), written);
         
         bufferSize <<= 1;
         buffer.resize(bufferSize);
@@ -396,7 +406,7 @@ String String::format(const char *format, ...)
 
     va_end(args);
     
-    return StringImpl::create(buffer.data(), len);
+    return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), len);
 #endif
 }
 
@@ -717,7 +727,7 @@ CString String::utf8(bool strict) const
     return CString(bufferVector.data(), buffer - bufferVector.data());
 }
 
-String String::fromUTF8(const char* stringStart, size_t length)
+String String::fromUTF8(const LChar* stringStart, size_t length)
 {
     if (length > numeric_limits<unsigned>::max())
         CRASH();
@@ -732,8 +742,8 @@ String String::fromUTF8(const char* stringStart, size_t length)
     UChar* bufferEnd = buffer + length;
 
     // Try converting into the buffer.
-    const char* stringCurrent = stringStart;
-    if (convertUTF8ToUTF16(&stringCurrent, stringStart + length, &buffer, bufferEnd) != conversionOK)
+    const char* stringCurrent = reinterpret_cast<const char*>(stringStart);
+    if (convertUTF8ToUTF16(&stringCurrent, reinterpret_cast<const char *>(stringStart + length), &buffer, bufferEnd) != conversionOK)
         return String();
 
     // stringBuffer is full (the input must have been all ascii) so just return it!
@@ -746,14 +756,14 @@ String String::fromUTF8(const char* stringStart, size_t length)
     return String(stringBuffer.characters(), utf16Length);
 }
 
-String String::fromUTF8(const char* string)
+String String::fromUTF8(const LChar* string)
 {
     if (!string)
         return String();
-    return fromUTF8(string, strlen(string));
+    return fromUTF8(string, strlen(reinterpret_cast<const char*>(string)));
 }
 
-String String::fromUTF8WithLatin1Fallback(const char* string, size_t size)
+String String::fromUTF8WithLatin1Fallback(const LChar* string, size_t size)
 {
     String utf8 = fromUTF8(string, size);
     if (!utf8)
index 3b98c19..78721d4 100644 (file)
@@ -89,9 +89,11 @@ public:
     WTF_EXPORT_PRIVATE String(const UChar*);
 
     // Construct a string with latin1 data.
+    WTF_EXPORT_PRIVATE String(const LChar* characters, unsigned length);
     WTF_EXPORT_PRIVATE String(const char* characters, unsigned length);
 
     // Construct a string with latin1 data, from a null-terminated source.
+    WTF_EXPORT_PRIVATE String(const LChar* characters);
     WTF_EXPORT_PRIVATE String(const char* characters);
 
     // Construct a string referencing an existing StringImpl.
@@ -155,7 +157,7 @@ public:
         { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
     size_t find(CharacterMatchFunctionPtr matchFunction, unsigned start = 0) const
         { return m_impl ? m_impl->find(matchFunction, start) : notFound; }
-    size_t find(const char* str, unsigned start = 0) const
+    size_t find(const LChar* str, unsigned start = 0) const
         { return m_impl ? m_impl->find(str, start) : notFound; }
 
     // Find the last instance of a single character or string.
@@ -165,7 +167,7 @@ public:
         { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; }
 
     // Case insensitive string matching.
-    WTF_EXPORT_PRIVATE size_t findIgnoringCase(const char* str, unsigned start = 0) const
+    WTF_EXPORT_PRIVATE size_t findIgnoringCase(const LChar* str, unsigned start = 0) const
         { return m_impl ? m_impl->findIgnoringCase(str, start) : notFound; }
     WTF_EXPORT_PRIVATE size_t findIgnoringCase(const String& str, unsigned start = 0) const
         { return m_impl ? m_impl->findIgnoringCase(str.impl(), start) : notFound; }
@@ -173,7 +175,7 @@ public:
         { return m_impl ? m_impl->reverseFindIgnoringCase(str.impl(), start) : notFound; }
 
     // Wrappers for find & reverseFind adding dynamic sensitivity check.
-    size_t find(const char* str, unsigned start, bool caseSensitive) const
+    size_t find(const LChar* str, unsigned start, bool caseSensitive) const
         { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
     size_t find(const String& str, unsigned start, bool caseSensitive) const
         { return caseSensitive ? find(str, start) : findIgnoringCase(str, start); }
@@ -185,7 +187,7 @@ public:
     WTF_EXPORT_PRIVATE UChar32 characterStartingAt(unsigned) const; // Ditto.
     
     bool contains(UChar c) const { return find(c) != notFound; }
-    bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
+    bool contains(const LChar* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
     bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
 
     bool startsWith(const String& s, bool caseSensitive = true) const
@@ -194,7 +196,8 @@ public:
         { return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); }
 
     WTF_EXPORT_PRIVATE void append(const String&);
-    WTF_EXPORT_PRIVATE void append(char);
+    WTF_EXPORT_PRIVATE void append(LChar);
+    inline WTF_EXPORT_PRIVATE void append(char c) { append(static_cast<LChar>(c)); };
     WTF_EXPORT_PRIVATE void append(UChar);
     WTF_EXPORT_PRIVATE void append(const UChar*, unsigned length);
     WTF_EXPORT_PRIVATE void insert(const String&, unsigned pos);
@@ -299,11 +302,14 @@ public:
 
     // String::fromUTF8 will return a null string if
     // the input data contains invalid UTF-8 sequences.
-    WTF_EXPORT_PRIVATE static String fromUTF8(const char*, size_t);
-    WTF_EXPORT_PRIVATE static String fromUTF8(const char*);
+    WTF_EXPORT_PRIVATE static String fromUTF8(const LChar*, size_t);
+    WTF_EXPORT_PRIVATE static String fromUTF8(const LChar*);
+    inline WTF_EXPORT_PRIVATE static String fromUTF8(const char* s, size_t length) { return fromUTF8(reinterpret_cast<const LChar*>(s), length); };
+    inline WTF_EXPORT_PRIVATE static String fromUTF8(const char* s) { return fromUTF8(reinterpret_cast<const LChar*>(s)); };
 
     // Tries to convert the passed in string to UTF-8, but will fall back to Latin-1 if the string is not valid UTF-8.
-    WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(const char*, size_t);
+    WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(const LChar*, size_t);
+    inline WTF_EXPORT_PRIVATE static String fromUTF8WithLatin1Fallback(const char* s, size_t length) { return fromUTF8WithLatin1Fallback(reinterpret_cast<const LChar*>(s), length); };
     
     // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
     WTF::Unicode::Direction defaultWritingDirection(bool* hasStrongDirectionality = 0) const
@@ -338,16 +344,22 @@ QDataStream& operator>>(QDataStream& stream, String& str);
 inline String& operator+=(String& a, const String& b) { a.append(b); return a; }
 
 inline bool operator==(const String& a, const String& b) { return equal(a.impl(), b.impl()); }
-inline bool operator==(const String& a, const char* b) { return equal(a.impl(), b); }
-inline bool operator==(const char* a, const String& b) { return equal(a, b.impl()); }
+inline bool operator==(const String& a, const LChar* b) { return equal(a.impl(), b); }
+inline bool operator==(const String& a, const char* b) { return equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool operator==(const LChar* a, const String& b) { return equal(a, b.impl()); }
+inline bool operator==(const char* a, const String& b) { return equal(reinterpret_cast<const LChar*>(a), b.impl()); }
 
 inline bool operator!=(const String& a, const String& b) { return !equal(a.impl(), b.impl()); }
-inline bool operator!=(const String& a, const char* b) { return !equal(a.impl(), b); }
-inline bool operator!=(const char* a, const String& b) { return !equal(a, b.impl()); }
+inline bool operator!=(const String& a, const LChar* b) { return !equal(a.impl(), b); }
+inline bool operator!=(const String& a, const char* b) { return !equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool operator!=(const LChar* a, const String& b) { return !equal(a, b.impl()); }
+inline bool operator!=(const char* a, const String& b) { return !equal(reinterpret_cast<const LChar*>(a), b.impl()); }
 
 inline bool equalIgnoringCase(const String& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); }
-inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), b); }
-inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const String& a, const LChar* b) { return equalIgnoringCase(a.impl(), b); }
+inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); }
+inline bool equalIgnoringCase(const LChar* a, const String& b) { return equalIgnoringCase(a, b.impl()); }
+inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(a), b.impl()); }
 
 inline bool equalPossiblyIgnoringCase(const String& a, const String& b, bool ignoreCase) 
 {
index c755c6c..f1d0dcf 100644 (file)
@@ -39,4 +39,7 @@
 
 COMPILE_ASSERT(sizeof(UChar) == 2, UCharIsTwoBytes);
 
+// Define platform neutral 8 bit character type (L is for Latin-1).
+typedef unsigned char LChar;
+
 #endif // WTF_UNICODE_H
index f4aef23..ef57f70 100644 (file)
@@ -2500,7 +2500,7 @@ void jitCompile(YarrPattern& pattern, YarrCharSize charSize, JSGlobalData* globa
     YarrGenerator(pattern, charSize).compile(globalData, jitObject);
 }
 
-int execute(YarrCodeBlock& jitObject, const char* input, unsigned start, unsigned length, int* output)
+int execute(YarrCodeBlock& jitObject, const LChar* input, unsigned start, unsigned length, int* output)
 {
     return jitObject.execute(input, start, length, output);
 }
index 74e660e..211a9a4 100644 (file)
@@ -48,7 +48,7 @@ class ExecutablePool;
 namespace Yarr {
 
 class YarrCodeBlock {
-    typedef int (*YarrJITCode8)(const char* input, unsigned start, unsigned length, int* output) YARR_CALL;
+    typedef int (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
     typedef int (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
 
 public:
@@ -68,7 +68,7 @@ public:
     void set8BitCode(MacroAssembler::CodeRef ref) { m_ref8 = ref; }
     void set16BitCode(MacroAssembler::CodeRef ref) { m_ref16 = ref; }
 
-    int execute(const char* input, unsigned start, unsigned length, int* output)
+    int execute(const LChar* input, unsigned start, unsigned length, int* output)
     {
         ASSERT(has8BitCode());
         return reinterpret_cast<YarrJITCode8>(m_ref8.code().executableAddress())(input, start, length, output);
@@ -91,7 +91,7 @@ private:
 
 void jitCompile(YarrPattern&, YarrCharSize, JSGlobalData*, YarrCodeBlock& jitObject);
 int execute(YarrCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output);
-int execute(YarrCodeBlock& jitObject, const char* input, unsigned start, unsigned length, int* output);
+int execute(YarrCodeBlock& jitObject, const LChar* input, unsigned start, unsigned length, int* output);
 
 } } // namespace JSC::Yarr
 
index ae0f557..c7f0c06 100644 (file)
@@ -231,7 +231,7 @@ private:
         : m_delegate(delegate)
         , m_backReferenceLimit(backReferenceLimit)
         , m_err(NoError)
-        , m_data(pattern)
+        , m_data(pattern.characters16())
         , m_size(pattern.length())
         , m_index(0)
         , m_parenthesesNestingDepth(0)
@@ -793,7 +793,7 @@ private:
     Delegate& m_delegate;
     unsigned m_backReferenceLimit;
     ErrorCode m_err;
-    const UString& m_data;
+    const UChar* m_data;
     unsigned m_size;
     unsigned m_index;
     unsigned m_parenthesesNestingDepth;
index 92e36e6..c3caaec 100755 (executable)
@@ -1,3 +1,17 @@
+2011-10-27  Michael Saboff  <msaboff@apple.com>
+
+        Investigate storing strings in 8-bit buffers when possible
+        https://bugs.webkit.org/show_bug.cgi?id=66161
+
+        Changes to support 8 bit StringImpl changes.
+        
+        Reviewed by Geoffrey Garen.
+        
+        No new tests, refactored StringImpl for 8 bit strings.
+
+        * platform/text/cf/StringImplCF.cpp:
+        (WTF::StringImpl::createCFString):
+
 2011-10-27  Nat Duca  <nduca@chromium.org>
 
         [chromium] Encapsulate state machine parts of scheduling in CCSchedulerStateMachine
index 76a028e..19fed84 100644 (file)
@@ -136,13 +136,13 @@ CFStringRef StringImpl::createCFString()
 {
     CFAllocatorRef allocator = (m_length && isMainThread()) ? StringWrapperCFAllocator::allocator() : 0;
     if (!allocator)
-        return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(m_data), m_length);
+        return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(characters()), m_length);
 
     // Put pointer to the StringImpl in a global so the allocator can store it with the CFString.
     ASSERT(!StringWrapperCFAllocator::currentString);
     StringWrapperCFAllocator::currentString = this;
 
-    CFStringRef string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(m_data), m_length, kCFAllocatorNull);
+    CFStringRef string = CFStringCreateWithCharactersNoCopy(allocator, reinterpret_cast<const UniChar*>(characters()), m_length, kCFAllocatorNull);
 
     // The allocator cleared the global when it read it, but also clear it here just in case.
     ASSERT(!StringWrapperCFAllocator::currentString);
index 6b11bac..fd47614 100644 (file)
@@ -1,3 +1,14 @@
+2011-10-27  Michael Saboff  <msaboff@apple.com>
+
+        Investigate storing strings in 8-bit buffers when possible
+        https://bugs.webkit.org/show_bug.cgi?id=66161
+
+        Added export of StringImpl::getData16SlowCase for linking tests.
+
+        Reviewed by Geoffrey Garen.
+
+        * win/WebKit2.def:
+
 2011-10-27  Sam Weinig  <sam@webkit.org>
 
         Add allowsPlugIns property to WKBrowsingContextGroup
index 19c4543..1769305 100644 (file)
@@ -146,15 +146,17 @@ EXPORTS
         ?absoluteBoundingBoxRect@RenderObject@WebCore@@QBE?AVIntRect@2@_N@Z
         ?absoluteBoundingBoxRectIgnoringTransforms@RenderObject@WebCore@@QBE?AVIntRect@2@XZ
         ?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBD@Z
+        ?add@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PBE@Z
         ?addSlowCase@AtomicString@WTF@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@2@PAVStringImpl@2@@Z
         ?cacheDOMStructure@WebCore@@YAPAVStructure@JSC@@PAVJSDOMGlobalObject@1@PAV23@PBUClassInfo@3@@Z
         ?create@Range@WebCore@@SA?AV?$PassRefPtr@VRange@WebCore@@@WTF@@V?$PassRefPtr@VDocument@WebCore@@@4@V?$PassRefPtr@VNode@WebCore@@@4@H1H@Z
         ?create@ShadowContentElement@WebCore@@SA?AV?$PassRefPtr@VShadowContentElement@WebCore@@@WTF@@PAVDocument@2@@Z
         ?createWrapper@WebCore@@YA?AVJSValue@JSC@@PAVExecState@3@PAVJSDOMGlobalObject@1@PAVNode@1@@Z
         ?ensureShadowRoot@Element@WebCore@@QAEPAVShadowRoot@2@XZ
-        ?equal@WTF@@YA_NPBVStringImpl@1@PBD@Z
+        ?equal@WTF@@YA_NPBVStringImpl@1@PBE@Z
         ?externalRepresentation@WebCore@@YA?AVString@WTF@@PAVElement@1@I@Z
         ?getCachedDOMStructure@WebCore@@YAPAVStructure@JSC@@PAVJSDOMGlobalObject@1@PBUClassInfo@3@@Z
+        ?getData16SlowCase@StringImpl@WTF@@ABEPB_WXZ
         ?getElementById@TreeScope@WebCore@@QBEPAVElement@2@ABVAtomicString@WTF@@@Z
         ?getLocationAndLengthFromRange@TextIterator@WebCore@@SA_NPAVElement@2@PBVRange@2@AAI2@Z
         ?isPreloaded@CachedResourceLoader@WebCore@@QBE_NABVString@WTF@@@Z