Changeset 36006 in webkit


Ignore:
Timestamp:
Aug 30, 2008 11:58:07 PM (16 years ago)
Author:
Darin Adler
Message:

JavaScriptCore:

2008-08-30 Darin Adler <Darin Adler>

Reviewed by Maciej.

1.035x as fast on SunSpider overall.
1.127x as fast on SunSpider string tests.
1.910x as fast on SunSpider string-base64 test.

  • API/JSObjectRef.cpp: (JSObjectMakeFunction): Removed unneeded explicit construction of UString.
  • GNUmakefile.am: Added SmallStrings.h and SmallStrings.cpp.
  • JavaScriptCore.pri: Ditto.
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: Ditto.
  • JavaScriptCore.xcodeproj/project.pbxproj: Ditto.
  • JavaScriptCoreSources.bkl: Ditto.
  • VM/Machine.cpp: (KJS::jsAddSlowCase): Changed to use a code path that doesn't involve a UString constructor. This avoids an extra jump caused by the "in charge" vs. "not in charge" constructors. (KJS::jsAdd): Ditto. (KJS::jsTypeStringForValue): Adopted jsNontrivialString.
  • kjs/ArrayPrototype.cpp: (KJS::arrayProtoFuncToString): Adopted jsEmptyString. (KJS::arrayProtoFuncToLocaleString): Ditto. (KJS::arrayProtoFuncJoin): Ditto.
  • kjs/BooleanPrototype.cpp: (KJS::booleanProtoFuncToString): Adopted jsNontrivialString.
  • kjs/DateConstructor.cpp: (KJS::callDate): Ditto.
  • kjs/DatePrototype.cpp: (KJS::formatLocaleDate): Adopted jsEmptyString and jsNontrivialString. (KJS::dateProtoFuncToString): Ditto. (KJS::dateProtoFuncToUTCString): Ditto. (KJS::dateProtoFuncToDateString): Ditto. (KJS::dateProtoFuncToTimeString): Ditto. (KJS::dateProtoFuncToLocaleString): Ditto. (KJS::dateProtoFuncToLocaleDateString): Ditto. (KJS::dateProtoFuncToLocaleTimeString): Ditto. (KJS::dateProtoFuncToGMTString): Ditto.
  • kjs/ErrorPrototype.cpp: (KJS::ErrorPrototype::ErrorPrototype): Ditto. (KJS::errorProtoFuncToString): Ditto.
  • kjs/JSGlobalData.h: Added SmallStrings.
  • kjs/JSString.cpp: (KJS::jsString): Eliminated the overload that takes a const char*. Added code to use SmallStrings to get strings of small sizes rather than creating a new JSString every time. (KJS::jsSubstring): Added. Used when creating a string from a substring to avoid creating a JSString in cases where the substring will end up empty or as one character. (KJS::jsOwnedString): Added the same code as in jsString.
  • kjs/JSString.h: Added new functions jsEmptyString, jsSingleCharacterString, jsSingleCharacterSubstring, jsSubstring, and jsNontrivialString for various cases where we want to create JSString, and want special handling for small strings. (KJS::JSString::JSString): Added an overload that takes a PassRefPtr of a UString::Rep so you don't have to construct a UString; PassRefPtr can be more efficient. (KJS::jsEmptyString): Added. (KJS::jsSingleCharacterString): Added. (KJS::jsSingleCharacterSubstring): Added. (KJS::jsNontrivialString): Added. (KJS::JSString::getIndex): Adopted jsSingleCharacterSubstring. (KJS::JSString::getStringPropertySlot): Ditto.
  • kjs/NumberPrototype.cpp: (KJS::numberProtoFuncToFixed): Adopted jsNontrivialString. (KJS::numberProtoFuncToExponential): Ditto. (KJS::numberProtoFuncToPrecision): Ditto.
  • kjs/ObjectPrototype.cpp: (KJS::objectProtoFuncToLocaleString): Adopted toThisJSString. (KJS::objectProtoFuncToString): Adopted jsNontrivialString.
  • kjs/RegExpConstructor.cpp: Separated the lastInput value that's used with the lastOvector to return matches from the input value that can be changed via JavaScript. They will be equal in many cases, but not all. (KJS::RegExpConstructor::performMatch): Set input. (KJS::RegExpMatchesArray::RegExpMatchesArray): Ditto. (KJS::RegExpMatchesArray::fillArrayInstance): Adopted jsSubstring. Also, use input rather than lastInput in the appropriate place. (KJS::RegExpConstructor::getBackref): Adopted jsSubstring and jsEmptyString. Added code to handle the case where there is no backref -- before this depended on range checking in UString::substr which is not present in jsSubstring. (KJS::RegExpConstructor::getLastParen): Ditto. (KJS::RegExpConstructor::getLeftContext): Ditto. (KJS::RegExpConstructor::getRightContext): Ditto. (KJS::RegExpConstructor::getValueProperty): Use input rather than lastInput. Also adopt jsEmptyString. (KJS::RegExpConstructor::putValueProperty): Ditto. (KJS::RegExpConstructor::input): Ditto.
  • kjs/RegExpPrototype.cpp: (KJS::regExpProtoFuncToString): Adopt jsNonTrivialString. Also changed to use UString::append to append single characters rather than using += and a C-style string.
  • kjs/SmallStrings.cpp: Added. (KJS::SmallStringsStorage::SmallStringsStorage): Construct the buffer and UString::Rep for all 256 single-character strings for the U+0000 through U+00FF. This covers all the values used in the base64 test as well as most values seen elsewhere on the web as well. It's possible that later we might fix this to only work for U+0000 through U+007F but the others are used quite a bit in the current version of the base64 test. (KJS::SmallStringsStorage::~SmallStringsStorage): Free memory. (KJS::SmallStrings::SmallStrings): Create a set of small strings, initially not created; created later when they are used. (KJS::SmallStrings::~SmallStrings): Deallocate. Not left compiler generated because the SmallStringsStorage class's destructor needs to be visible. (KJS::SmallStrings::mark): Mark all the strings. (KJS::SmallStrings::createEmptyString): Create a cell for the empty string. Called only the first time. (KJS::SmallStrings::createSingleCharacterString): Create a cell for one of the single-character strings. Called only the first time.
  • kjs/SmallStrings.h: Added.
  • kjs/StringConstructor.cpp: (KJS::stringFromCharCodeSlowCase): Factored out of strinFromCharCode. Only used for cases where the caller does not pass exactly one argument. (KJS::stringFromCharCode): Adopted jsSingleCharacterString. (KJS::callStringConstructor): Adopted jsEmptyString.
  • kjs/StringObject.cpp: (KJS::StringObject::StringObject): Adopted jsEmptyString.
  • kjs/StringPrototype.cpp: (KJS::stringProtoFuncReplace): Adopted jsSubstring. (KJS::stringProtoFuncCharAt): Adopted jsEmptyString and jsSingleCharacterSubstring and also added a special case when the index is an immediate number to avoid conversion to and from floating point, since that's the common case. (KJS::stringProtoFuncCharCodeAt): Ditto. (KJS::stringProtoFuncMatch): Adopted jsSubstring and jsEmptyString. (KJS::stringProtoFuncSlice): Adopted jsSubstring and jsSingleCharacterSubstring. Also got rid of some unneeded locals and removed unneeded code to set the length property of the array, since it is automatically updated as values are added to the array. (KJS::stringProtoFuncSplit): Adopted jsEmptyString. (KJS::stringProtoFuncSubstr): Adopted jsSubstring. (KJS::stringProtoFuncSubstring): Ditto.
  • kjs/collector.cpp: (KJS::Heap::collect): Added a call to mark SmallStrings.
  • kjs/ustring.cpp: (KJS::UString::expandedSize): Made this a static member function since it doesn't need to look at any data members. (KJS::UString::expandCapacity): Use a non-inline function, makeNull, to set the rep to null in failure cases. This avoids adding a PIC branch for the normal case when there is no failure. (KJS::UString::expandPreCapacity): Ditto. (KJS::UString::UString): Ditto. (KJS::concatenate): Refactored the concatenation constructor into this separate function. Calling the concatenation constructor was leading to an extra branch because of the in-charge vs. not-in-charge versions not both being inlined, and this was showing up as nearly 1% on Shark. Also added a special case for when the second string is a single character, since it's a common idiom to build up a string that way and we can do things much more quickly, without involving memcpy for example. Also adopted the non-inline function, nullRep, for the same reason given for makeNull above. (KJS::UString::append): Adopted makeNull for failure cases. (KJS::UString::operator=): Ditto. (KJS::UString::toDouble): Added a special case for converting single character strings to numbers. We're doing this a ton of times while running the base64 test. (KJS::operator==): Added special cases so we can compare single-character strings without calling memcmp. Later we might want to special case other short lengths similarly. (KJS::UString::makeNull): Added. (KJS::UString::nullRep): Added.
  • kjs/ustring.h: Added declarations for the nullRep and makeNull. Changed expandedSize to be a static member function. Added a declaration of the concatenate function. Removed the concatenation constructor. Rewrote operator+ to use the concatenate function.

WebCore:

2008-08-30 Darin Adler <Darin Adler>

Reviewed by Maciej.

  • bindings/js/JSDOMWindowBase.cpp: (WebCore::windowProtoFuncAToB): Adopted jsEmptyString. (WebCore::windowProtoFuncBToA): Ditto.
  • bindings/js/JSEventListener.cpp: (WebCore::JSLazyEventListener::eventParameterName): Adopted jsNontrivialString.
  • bindings/js/JSSVGLazyEventListener.cpp: (WebCore::JSSVGLazyEventListener::eventParameterName): Ditto.

LayoutTests:

2008-08-30 Darin Adler <Darin Adler>

Reviewed by Maciej.

  • updated incorrect results that reflected a bug in the RegExp object
  • fast/js/regexp-caching-expected.txt: Updated results to correctly show that $1 through $9, lastMatch, lastParen, leftContext, and rightContext are left alone both when a program changes the value of RegExp.input and when it performs an unsuccessful match. The new results match Gecko behavior (I tested both Firefox 2 and 3).
Location:
trunk
Files:
2 added
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSObjectRef.cpp

    r35900 r36006  
    118118    ArgList args;
    119119    for (unsigned i = 0; i < parameterCount; i++)
    120         args.append(jsString(exec, UString(parameterNames[i]->ustring())));
     120        args.append(jsString(exec, parameterNames[i]->ustring()));
    121121    args.append(jsString(exec, body->ustring()));
    122122
  • trunk/JavaScriptCore/ChangeLog

    r36004 r36006  
     12008-08-30  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Maciej.
     4
     5        - https://bugs.webkit.org/show_bug.cgi?id=20333
     6          improve JavaScript speed when handling single-character strings
     7
     8        1.035x as fast on SunSpider overall.
     9        1.127x as fast on SunSpider string tests.
     10        1.910x as fast on SunSpider string-base64 test.
     11
     12        * API/JSObjectRef.cpp:
     13        (JSObjectMakeFunction): Removed unneeded explicit construction of UString.
     14
     15        * GNUmakefile.am: Added SmallStrings.h and SmallStrings.cpp.
     16        * JavaScriptCore.pri: Ditto.
     17        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
     18        Ditto.
     19        * JavaScriptCore.xcodeproj/project.pbxproj: Ditto.
     20        * JavaScriptCoreSources.bkl: Ditto.
     21
     22        * JavaScriptCore.exp: Updated.
     23
     24        * VM/Machine.cpp:
     25        (KJS::jsAddSlowCase): Changed to use a code path that doesn't involve
     26        a UString constructor. This avoids an extra jump caused by the "in charge"
     27        vs. "not in charge" constructors.
     28        (KJS::jsAdd): Ditto.
     29        (KJS::jsTypeStringForValue): Adopted jsNontrivialString.
     30
     31        * kjs/ArrayPrototype.cpp:
     32        (KJS::arrayProtoFuncToString): Adopted jsEmptyString.
     33        (KJS::arrayProtoFuncToLocaleString): Ditto.
     34        (KJS::arrayProtoFuncJoin): Ditto.
     35        * kjs/BooleanPrototype.cpp:
     36        (KJS::booleanProtoFuncToString): Adopted jsNontrivialString.
     37        * kjs/DateConstructor.cpp:
     38        (KJS::callDate): Ditto.
     39        * kjs/DatePrototype.cpp:
     40        (KJS::formatLocaleDate): Adopted jsEmptyString and jsNontrivialString.
     41        (KJS::dateProtoFuncToString): Ditto.
     42        (KJS::dateProtoFuncToUTCString): Ditto.
     43        (KJS::dateProtoFuncToDateString): Ditto.
     44        (KJS::dateProtoFuncToTimeString): Ditto.
     45        (KJS::dateProtoFuncToLocaleString): Ditto.
     46        (KJS::dateProtoFuncToLocaleDateString): Ditto.
     47        (KJS::dateProtoFuncToLocaleTimeString): Ditto.
     48        (KJS::dateProtoFuncToGMTString): Ditto.
     49
     50        * kjs/ErrorPrototype.cpp:
     51        (KJS::ErrorPrototype::ErrorPrototype): Ditto.
     52        (KJS::errorProtoFuncToString): Ditto.
     53
     54        * kjs/JSGlobalData.h: Added SmallStrings.
     55
     56        * kjs/JSString.cpp:
     57        (KJS::jsString): Eliminated the overload that takes a const char*.
     58        Added code to use SmallStrings to get strings of small sizes rather
     59        than creating a new JSString every time.
     60        (KJS::jsSubstring): Added. Used when creating a string from a substring
     61        to avoid creating a JSString in cases where the substring will end up
     62        empty or as one character.
     63        (KJS::jsOwnedString): Added the same code as in jsString.
     64
     65        * kjs/JSString.h: Added new functions jsEmptyString, jsSingleCharacterString,
     66        jsSingleCharacterSubstring, jsSubstring, and jsNontrivialString for various
     67        cases where we want to create JSString, and want special handling for small
     68        strings.
     69        (KJS::JSString::JSString): Added an overload that takes a PassRefPtr of
     70        a UString::Rep so you don't have to construct a UString; PassRefPtr can be
     71        more efficient.
     72        (KJS::jsEmptyString): Added.
     73        (KJS::jsSingleCharacterString): Added.
     74        (KJS::jsSingleCharacterSubstring): Added.
     75        (KJS::jsNontrivialString): Added.
     76        (KJS::JSString::getIndex): Adopted jsSingleCharacterSubstring.
     77        (KJS::JSString::getStringPropertySlot): Ditto.
     78
     79        * kjs/NumberPrototype.cpp:
     80        (KJS::numberProtoFuncToFixed): Adopted jsNontrivialString.
     81        (KJS::numberProtoFuncToExponential): Ditto.
     82        (KJS::numberProtoFuncToPrecision): Ditto.
     83
     84        * kjs/ObjectPrototype.cpp:
     85        (KJS::objectProtoFuncToLocaleString): Adopted toThisJSString.
     86        (KJS::objectProtoFuncToString): Adopted jsNontrivialString.
     87
     88        * kjs/RegExpConstructor.cpp: Separated the lastInput value that's used
     89        with the lastOvector to return matches from the input value that can be
     90        changed via JavaScript. They will be equal in many cases, but not all.
     91        (KJS::RegExpConstructor::performMatch): Set input.
     92        (KJS::RegExpMatchesArray::RegExpMatchesArray): Ditto.
     93        (KJS::RegExpMatchesArray::fillArrayInstance): Adopted jsSubstring. Also,
     94        use input rather than lastInput in the appropriate place.
     95        (KJS::RegExpConstructor::getBackref): Adopted jsSubstring and jsEmptyString.
     96        Added code to handle the case where there is no backref -- before this
     97        depended on range checking in UString::substr which is not present in
     98        jsSubstring.
     99        (KJS::RegExpConstructor::getLastParen): Ditto.
     100        (KJS::RegExpConstructor::getLeftContext): Ditto.
     101        (KJS::RegExpConstructor::getRightContext): Ditto.
     102        (KJS::RegExpConstructor::getValueProperty): Use input rather than lastInput.
     103        Also adopt jsEmptyString.
     104        (KJS::RegExpConstructor::putValueProperty): Ditto.
     105        (KJS::RegExpConstructor::input): Ditto.
     106
     107        * kjs/RegExpPrototype.cpp:
     108        (KJS::regExpProtoFuncToString): Adopt jsNonTrivialString. Also changed to
     109        use UString::append to append single characters rather than using += and
     110        a C-style string.
     111
     112        * kjs/SmallStrings.cpp: Added.
     113        (KJS::SmallStringsStorage::SmallStringsStorage): Construct the
     114        buffer and UString::Rep for all 256 single-character strings for
     115        the U+0000 through U+00FF. This covers all the values used in
     116        the base64 test as well as most values seen elsewhere on the web
     117        as well. It's possible that later we might fix this to only work
     118        for U+0000 through U+007F but the others are used quite a bit in
     119        the current version of the base64 test.
     120        (KJS::SmallStringsStorage::~SmallStringsStorage): Free memory.
     121        (KJS::SmallStrings::SmallStrings): Create a set of small strings,
     122        initially not created; created later when they are used.
     123        (KJS::SmallStrings::~SmallStrings): Deallocate. Not left compiler
     124        generated because the SmallStringsStorage class's destructor needs
     125        to be visible.
     126        (KJS::SmallStrings::mark): Mark all the strings.
     127        (KJS::SmallStrings::createEmptyString): Create a cell for the
     128        empty string. Called only the first time.
     129        (KJS::SmallStrings::createSingleCharacterString): Create a cell
     130        for one of the single-character strings. Called only the first time.
     131        * kjs/SmallStrings.h: Added.
     132
     133        * kjs/StringConstructor.cpp:
     134        (KJS::stringFromCharCodeSlowCase): Factored out of strinFromCharCode.
     135        Only used for cases where the caller does not pass exactly one argument.
     136        (KJS::stringFromCharCode): Adopted jsSingleCharacterString.
     137        (KJS::callStringConstructor): Adopted jsEmptyString.
     138
     139        * kjs/StringObject.cpp:
     140        (KJS::StringObject::StringObject): Adopted jsEmptyString.
     141
     142        * kjs/StringPrototype.cpp:
     143        (KJS::stringProtoFuncReplace): Adopted jsSubstring.
     144        (KJS::stringProtoFuncCharAt): Adopted jsEmptyString and
     145        jsSingleCharacterSubstring and also added a special case when the
     146        index is an immediate number to avoid conversion to and from floating
     147        point, since that's the common case.
     148        (KJS::stringProtoFuncCharCodeAt): Ditto.
     149        (KJS::stringProtoFuncMatch): Adopted jsSubstring and jsEmptyString.
     150        (KJS::stringProtoFuncSlice): Adopted jsSubstring and
     151        jsSingleCharacterSubstring. Also got rid of some unneeded locals and
     152        removed unneeded code to set the length property of the array, since it
     153        is automatically updated as values are added to the array.
     154        (KJS::stringProtoFuncSplit): Adopted jsEmptyString.
     155        (KJS::stringProtoFuncSubstr): Adopted jsSubstring.
     156        (KJS::stringProtoFuncSubstring): Ditto.
     157
     158        * kjs/collector.cpp:
     159        (KJS::Heap::collect): Added a call to mark SmallStrings.
     160
     161        * kjs/ustring.cpp:
     162        (KJS::UString::expandedSize): Made this a static member function since
     163        it doesn't need to look at any data members.
     164        (KJS::UString::expandCapacity): Use a non-inline function, makeNull, to
     165        set the rep to null in failure cases. This avoids adding a PIC branch for
     166        the normal case when there is no failure.
     167        (KJS::UString::expandPreCapacity): Ditto.
     168        (KJS::UString::UString): Ditto.
     169        (KJS::concatenate): Refactored the concatenation constructor into this
     170        separate function. Calling the concatenation constructor was leading to
     171        an extra branch because of the in-charge vs. not-in-charge versions not
     172        both being inlined, and this was showing up as nearly 1% on Shark. Also
     173        added a special case for when the second string is a single character,
     174        since it's a common idiom to build up a string that way and we can do
     175        things much more quickly, without involving memcpy for example. Also
     176        adopted the non-inline function, nullRep, for the same reason given for
     177        makeNull above.
     178        (KJS::UString::append): Adopted makeNull for failure cases.
     179        (KJS::UString::operator=): Ditto.
     180        (KJS::UString::toDouble): Added a special case for converting single
     181        character strings to numbers. We're doing this a ton of times while
     182        running the base64 test.
     183        (KJS::operator==): Added special cases so we can compare single-character
     184        strings without calling memcmp. Later we might want to special case other
     185        short lengths similarly.
     186        (KJS::UString::makeNull): Added.
     187        (KJS::UString::nullRep): Added.
     188        * kjs/ustring.h: Added declarations for the nullRep and makeNull. Changed
     189        expandedSize to be a static member function. Added a declaration of the
     190        concatenate function. Removed the concatenation constructor. Rewrote
     191        operator+ to use the concatenate function.
     192
    11932008-08-29  Anders Carlsson  <andersca@apple.com>
    2194
  • trunk/JavaScriptCore/GNUmakefile.am

    r35985 r36006  
    175175        JavaScriptCore/kjs/ScopeChain.h \
    176176        JavaScriptCore/kjs/ScopeChainMark.h \
     177        JavaScriptCore/kjs/SmallStrings.h \
    177178        JavaScriptCore/kjs/SourceProvider.h \
    178179        JavaScriptCore/kjs/SourceRange.h \
     
    344345        JavaScriptCore/kjs/RegExpPrototype.cpp \
    345346        JavaScriptCore/kjs/ScopeChain.cpp \
     347        JavaScriptCore/kjs/SmallStrings.cpp \
    346348        JavaScriptCore/kjs/StringConstructor.cpp \
    347349        JavaScriptCore/kjs/StringObject.cpp \
  • trunk/JavaScriptCore/JavaScriptCore.exp

    r35930 r36006  
    114114__ZN3KJS12SamplingTool4stopEv
    115115__ZN3KJS12SamplingTool5startEj
     116__ZN3KJS12SmallStrings17createEmptyStringEPNS_9ExecStateE
    116117__ZN3KJS12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
    117118__ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE
     
    233234__ZN3KJS8Profiler21didFinishAllExecutionEPNS_9ExecStateE
    234235__ZN3KJS8Profiler8profilerEv
    235 __ZN3KJS8jsStringEPNS_9ExecStateEPKc
    236236__ZN3KJS8jsStringEPNS_9ExecStateERKNS_7UStringE
    237237__ZN3KJS9constructEPNS_9ExecStateEPNS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE
     
    335335__ZTVN3KJS16JSVariableObjectE
    336336__ZTVN3KJS8JSObjectE
     337__ZTVN3KJS8JSStringE
    337338_jscore_fastmalloc_introspection
    338339_kJSClassDefinitionEmpty
  • trunk/JavaScriptCore/JavaScriptCore.pri

    r35853 r36006  
    132132    kjs/RegExpPrototype.cpp \
    133133    kjs/ScopeChain.cpp \
     134    kjs/SmallStrings.cpp \
    134135    kjs/StringConstructor.cpp \
    135136    kjs/StringObject.cpp \
  • trunk/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj

    r35853 r36006  
    838838                        </File>
    839839                        <File
    840                                 RelativePath="..\..\kjs\simple_number.h"
     840                                RelativePath="..\..\kjs\SmallStrings.h"
     841                                >
     842                        </File>
     843                        <File
     844                                RelativePath="..\..\kjs\SmallStrings.cpp"
    841845                                >
    842846                        </File>
  • trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r35984 r36006  
    6868                14E0FF120DBAAED00007C0AB /* Machine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 149B15E70D81F986009CB8C7 /* Machine.cpp */; settings = {COMPILER_FLAGS = "-fno-tree-pre"; }; };
    6969                5D53726F0E1C54880021E549 /* Tracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53726E0E1C54880021E549 /* Tracing.h */; };
    70                 5D53727E0E1C55EC0021E549 /* TracingDtrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53727D0E1C55EC0021E549 /* TracingDtrace.h */; };
    7170                5D5D8AB60E0D0A7200F9C692 /* jsc in Copy Into Framework */ = {isa = PBXBuildFile; fileRef = 932F5BE10822A1C700736975 /* jsc */; };
    7271                5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; };
     
    8988                932F5BDD0822A1C700736975 /* Shell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45E12D8806A49B0F00E9DF84 /* Shell.cpp */; };
    9089                932F5BEA0822A1C700736975 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
     90                933040040E6A749400786E6A /* SmallStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 93303FEA0E6A72C000786E6A /* SmallStrings.h */; settings = {ATTRIBUTES = (Private, ); }; };
     91                9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93303FE80E6A72B500786E6A /* SmallStrings.cpp */; };
    9192                937013480CA97E0E00FA14D3 /* pcre_ucp_searchfuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 937013470CA97E0E00FA14D3 /* pcre_ucp_searchfuncs.cpp */; settings = {COMPILER_FLAGS = "-Wno-sign-compare"; }; };
    9293                93E26BD408B1514100F85226 /* pcre_xclass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E26BD308B1514100F85226 /* pcre_xclass.cpp */; };
     
    577578                932F5BD90822A1C700736975 /* JavaScriptCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
    578579                932F5BE10822A1C700736975 /* jsc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jsc; sourceTree = BUILT_PRODUCTS_DIR; };
     580                93303FE80E6A72B500786E6A /* SmallStrings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallStrings.cpp; sourceTree = "<group>"; };
     581                93303FEA0E6A72C000786E6A /* SmallStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallStrings.h; sourceTree = "<group>"; };
    579582                933A3499038AE7C6008635CE /* grammar.y */ = {isa = PBXFileReference; explicitFileType = sourcecode.yacc; fileEncoding = 4; indentWidth = 4; path = grammar.y; sourceTree = "<group>"; tabWidth = 8; };
    580583                933A349A038AE7C6008635CE /* identifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = identifier.h; sourceTree = "<group>"; tabWidth = 8; };
     
    12441247                                9374D3A7038D9D74008635CE /* ScopeChain.h */,
    12451248                                7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */,
     1249                                93303FE80E6A72B500786E6A /* SmallStrings.cpp */,
     1250                                93303FEA0E6A72C000786E6A /* SmallStrings.h */,
    12461251                                65E866ED0DD59AFA00A2B2A1 /* SourceProvider.h */,
    12471252                                65E866EE0DD59AFA00A2B2A1 /* SourceRange.h */,
     
    15201525                                95CD45770E1C4FDD0085358E /* ProfileGenerator.h in Headers */,
    15211526                                5D53726F0E1C54880021E549 /* Tracing.h in Headers */,
    1522                                 5D53727E0E1C55EC0021E549 /* TracingDtrace.h in Headers */,
    15231527                                BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */,
    15241528                                BC3046070E1F497F003232CF /* Error.h in Headers */,
     
    15341538                                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
    15351539                                9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */,
     1540                                933040040E6A749400786E6A /* SmallStrings.h in Headers */,
    15361541                        );
    15371542                        runOnlyForDeploymentPostprocessing = 0;
     
    18401845                                E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */,
    18411846                                95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */,
     1847                                9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
    18421848                        );
    18431849                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/JavaScriptCore/JavaScriptCoreSources.bkl

    r35853 r36006  
    118118        kjs/RegExpPrototype.cpp
    119119        kjs/ScopeChain.cpp
     120        kjs/SmallStrings.cpp
    120121        kjs/StringConstructor.cpp
    121122        kjs/StringObject.cpp
  • trunk/JavaScriptCore/VM/Machine.cpp

    r36004 r36006  
    192192
    193193    if (p1->isString() || p2->isString()) {
    194         UString value = p1->toString(exec) + p2->toString(exec);
    195         if (value.isNull())
     194        RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
     195        if (!value)
    196196            return throwOutOfMemoryError(exec);
    197         return jsString(exec, value);
     197        return jsString(exec, value.release());
    198198    }
    199199
     
    218218   
    219219    if (v1->isString() && v2->isString()) {
    220         UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
    221         if (value.isNull())
     220        RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
     221        if (!value)
    222222            return throwOutOfMemoryError(exec);
    223         return jsString(exec, value);
     223        return jsString(exec, value.release());
    224224    }
    225225
     
    231231{
    232232    if (v->isUndefined())
    233         return jsString(exec, "undefined");
     233        return jsNontrivialString(exec, "undefined");
    234234    if (v->isBoolean())
    235         return jsString(exec, "boolean");
     235        return jsNontrivialString(exec, "boolean");
    236236    if (v->isNumber())
    237         return jsString(exec, "number");
     237        return jsNontrivialString(exec, "number");
    238238    if (v->isString())
    239         return jsString(exec, "string");
     239        return jsNontrivialString(exec, "string");
    240240    if (v->isObject()) {
    241241        // Return "undefined" for objects that should be treated
    242242        // as null when doing comparisons.
    243243        if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
    244             return jsString(exec, "undefined");
     244            return jsNontrivialString(exec, "undefined");
    245245        CallData callData;
    246246        if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
    247             return jsString(exec, "function");
    248     }
    249     return jsString(exec, "object");
     247            return jsNontrivialString(exec, "function");
     248    }
     249    return jsNontrivialString(exec, "object");
    250250}
    251251
  • trunk/JavaScriptCore/kjs/ArrayPrototype.cpp

    r35807 r36006  
    127127    Vector<UChar, 256> strBuffer;
    128128    if (alreadyVisited)
    129         return jsString(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.
     129        return jsEmptyString(exec); // return an empty string, avoiding infinite recursion.
    130130
    131131    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     
    171171    Vector<UChar, 256> strBuffer;
    172172    if (alreadyVisited)
    173         return jsString(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.
     173        return jsEmptyString(exec); // return an empty string, avoding infinite recursion.
    174174
    175175    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     
    221221    Vector<UChar, 256> strBuffer;
    222222    if (alreadyVisited)
    223         return jsString(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.
     223        return jsEmptyString(exec); // return an empty string, avoding infinite recursion.
    224224
    225225    UChar comma = ',';
  • trunk/JavaScriptCore/kjs/BooleanPrototype.cpp

    r35807 r36006  
    5555{
    5656    if (thisValue == jsBoolean(false))
    57         return jsString(exec, "false");
     57        return jsNontrivialString(exec, "false");
    5858
    5959    if (thisValue == jsBoolean(true))
    60         return jsString(exec, "true");
     60        return jsNontrivialString(exec, "true");
    6161
    6262    if (!thisValue->isObject(&BooleanObject::info))
     
    6464
    6565    if (static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(false))
    66         return jsString(exec, "false");
     66        return jsNontrivialString(exec, "false");
    6767
    6868    ASSERT(static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(true));
    69     return jsString(exec, "true");
     69    return jsNontrivialString(exec, "true");
    7070}
    7171
  • trunk/JavaScriptCore/kjs/DateConstructor.cpp

    r35807 r36006  
    125125    getLocalTime(&localTime, &localTM);
    126126    GregorianDateTime ts(localTM);
    127     return jsString(exec, formatDate(ts) + " " + formatTime(ts, false));
     127    return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts, false));
    128128}
    129129
  • trunk/JavaScriptCore/kjs/DatePrototype.cpp

    r35807 r36006  
    195195 
    196196    if (ret == 0)
    197         return jsString(exec, "");
     197        return jsEmptyString(exec);
    198198 
    199199    // Copy original into the buffer
     
    209209    }
    210210 
    211     return jsString(exec, timebuffer);
     211    return jsNontrivialString(exec, timebuffer);
    212212}
    213213
     
    370370    double milli = thisDateObj->internalNumber();
    371371    if (isnan(milli))
    372         return jsString(exec, "Invalid Date");
    373 
    374     GregorianDateTime t;
    375     thisDateObj->msToGregorianDateTime(milli, utc, t);
    376     return jsString(exec, formatDate(t) + " " + formatTime(t, utc));
     372        return jsNontrivialString(exec, "Invalid Date");
     373
     374    GregorianDateTime t;
     375    thisDateObj->msToGregorianDateTime(milli, utc, t);
     376    return jsNontrivialString(exec, formatDate(t) + " " + formatTime(t, utc));
    377377}
    378378
     
    387387    double milli = thisDateObj->internalNumber();
    388388    if (isnan(milli))
    389         return jsString(exec, "Invalid Date");
    390 
    391     GregorianDateTime t;
    392     thisDateObj->msToGregorianDateTime(milli, utc, t);
    393     return jsString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc));
     389        return jsNontrivialString(exec, "Invalid Date");
     390
     391    GregorianDateTime t;
     392    thisDateObj->msToGregorianDateTime(milli, utc, t);
     393    return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc));
    394394}
    395395
     
    404404    double milli = thisDateObj->internalNumber();
    405405    if (isnan(milli))
    406         return jsString(exec, "Invalid Date");
    407 
    408     GregorianDateTime t;
    409     thisDateObj->msToGregorianDateTime(milli, utc, t);
    410     return jsString(exec, formatDate(t));
     406        return jsNontrivialString(exec, "Invalid Date");
     407
     408    GregorianDateTime t;
     409    thisDateObj->msToGregorianDateTime(milli, utc, t);
     410    return jsNontrivialString(exec, formatDate(t));
    411411}
    412412
     
    421421    double milli = thisDateObj->internalNumber();
    422422    if (isnan(milli))
    423         return jsString(exec, "Invalid Date");
    424 
    425     GregorianDateTime t;
    426     thisDateObj->msToGregorianDateTime(milli, utc, t);
    427     return jsString(exec, formatTime(t, utc));
     423        return jsNontrivialString(exec, "Invalid Date");
     424
     425    GregorianDateTime t;
     426    thisDateObj->msToGregorianDateTime(milli, utc, t);
     427    return jsNontrivialString(exec, formatTime(t, utc));
    428428}
    429429
     
    436436    double milli = thisDateObj->internalNumber();
    437437    if (isnan(milli))
    438         return jsString(exec, "Invalid Date");
     438        return jsNontrivialString(exec, "Invalid Date");
    439439
    440440#if PLATFORM(MAC)
    441441    double secs = floor(milli / msPerSecond);
    442     return jsString(exec, formatLocaleDate(exec, secs, true, true, args));
     442    return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, true, args));
    443443#else
    444444    UNUSED_PARAM(args);
     
    460460    double milli = thisDateObj->internalNumber();
    461461    if (isnan(milli))
    462         return jsString(exec, "Invalid Date");
     462        return jsNontrivialString(exec, "Invalid Date");
    463463
    464464#if PLATFORM(MAC)
    465465    double secs = floor(milli / msPerSecond);
    466     return jsString(exec, formatLocaleDate(exec, secs, true, false, args));
     466    return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, false, args));
    467467#else
    468468    UNUSED_PARAM(args);
     
    484484    double milli = thisDateObj->internalNumber();
    485485    if (isnan(milli))
    486         return jsString(exec, "Invalid Date");
     486        return jsNontrivialString(exec, "Invalid Date");
    487487
    488488#if PLATFORM(MAC)
    489489    double secs = floor(milli / msPerSecond);
    490     return jsString(exec, formatLocaleDate(exec, secs, false, true, args));
     490    return jsNontrivialString(exec, formatLocaleDate(exec, secs, false, true, args));
    491491#else
    492492    UNUSED_PARAM(args);
     
    570570    double milli = thisDateObj->internalNumber();
    571571    if (isnan(milli))
    572         return jsString(exec, "Invalid Date");
    573 
    574     GregorianDateTime t;
    575     thisDateObj->msToGregorianDateTime(milli, utc, t);
    576     return jsString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc));
     572        return jsNontrivialString(exec, "Invalid Date");
     573
     574    GregorianDateTime t;
     575    thisDateObj->msToGregorianDateTime(milli, utc, t);
     576    return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc));
    577577}
    578578
  • trunk/JavaScriptCore/kjs/ErrorPrototype.cpp

    r35807 r36006  
    4040    // The constructor will be added later in ErrorConstructor's constructor
    4141
    42     putDirect(exec->propertyNames().name, jsString(exec, "Error"), DontEnum);
    43     putDirect(exec->propertyNames().message, jsString(exec, "Unknown error"), DontEnum);
     42    putDirect(exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum);
     43    putDirect(exec->propertyNames().message, jsNontrivialString(exec, "Unknown error"), DontEnum);
    4444
    4545    putDirectFunction(exec, new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum);
     
    6363    }
    6464
    65     return jsString(exec, s);
     65    return jsNontrivialString(exec, s);
    6666}
    6767
  • trunk/JavaScriptCore/kjs/JSGlobalData.h

    r35853 r36006  
    3535#include <wtf/HashSet.h>
    3636#include <wtf/RefCounted.h>
     37#include "SmallStrings.h"
    3738
    3839struct OpaqueJSClass;
     
    7677        const ArgList* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark.
    7778
     79        SmallStrings smallStrings;
     80       
    7881        HashMap<OpaqueJSClass*, OpaqueJSClassContextData*>* opaqueJSClassData;
    7982
  • trunk/JavaScriptCore/kjs/JSString.cpp

    r35830 r36006  
    116116}
    117117
    118 JSString* jsString(ExecState* exec, const char* s)
    119 {
    120     return new (exec) JSString(s ? s : "");
    121 }
    122 
    123118JSString* jsString(ExecState* exec, const UString& s)
    124119{
    125     return s.isNull() ? new (exec) JSString("") : new (exec) JSString(s);
     120    int size = s.size();
     121    if (!size)
     122        return exec->globalData().smallStrings.emptyString(exec);
     123    if (size == 1) {
     124        UChar c = s.data()[0];
     125        if (c <= 0xFF)
     126            return exec->globalData().smallStrings.singleCharacterString(exec, c);
     127    }
     128    return new (exec) JSString(s);
     129}
     130   
     131JSString* jsSubstring(ExecState* exec, const UString& s, unsigned offset, unsigned length)
     132{
     133    ASSERT(offset <= static_cast<unsigned>(s.size()));
     134    ASSERT(length <= static_cast<unsigned>(s.size()));
     135    ASSERT(offset + length <= static_cast<unsigned>(s.size()));
     136    if (!length)
     137        return exec->globalData().smallStrings.emptyString(exec);
     138    if (length == 1) {
     139        UChar c = s.data()[offset];
     140        if (c <= 0xFF)
     141            return exec->globalData().smallStrings.singleCharacterString(exec, c);
     142    }
     143    return new (exec) JSString(UString::Rep::create(s.rep(), offset, length));
    126144}
    127145
    128146JSString* jsOwnedString(ExecState* exec, const UString& s)
    129147{
    130     return s.isNull() ? new (exec) JSString("", JSString::HasOtherOwner) : new (exec) JSString(s, JSString::HasOtherOwner);
     148    int size = s.size();
     149    if (!size)
     150        return exec->globalData().smallStrings.emptyString(exec);
     151    if (size == 1) {
     152        UChar c = s.data()[0];
     153        if (c <= 0xFF)
     154            return exec->globalData().smallStrings.singleCharacterString(exec, c);
     155    }
     156    return new (exec) JSString(s, JSString::HasOtherOwner);
    131157}
    132158
  • trunk/JavaScriptCore/kjs/JSString.h

    r35900 r36006  
    2626#include "CommonIdentifiers.h"
    2727#include "ExecState.h"
    28 #include "JSCell.h"
    2928#include "JSNumberCell.h"
    3029#include "PropertySlot.h"
    3130#include "identifier.h"
    32 #include "ustring.h"
    3331
    3432namespace KJS {
     33
     34    class JSString;
     35
     36    JSString* jsEmptyString(ExecState*);
     37    JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
     38
     39    JSString* jsSingleCharacterString(ExecState*, UChar);
     40    JSString* jsSingleCharacterSubstring(ExecState*, const UString&, unsigned offset);
     41    JSString* jsSubstring(ExecState*, const UString&, unsigned offset, unsigned length);
     42
     43    // Non-trivial strings are two or more characters long.
     44    // These functions are faster than just calling jsString.
     45    JSString* jsNontrivialString(ExecState*, const UString&);
     46    JSString* jsNontrivialString(ExecState*, const char*);
     47
     48    // Should be used for strings that are owned by an object that will
     49    // likely outlive the JSValue this makes, such as the parse tree or a
     50    // DOM object that contains a UString
     51    JSString* jsOwnedString(ExecState*, const UString&);
    3552
    3653    class JSString : public JSCell {
     
    4764        {
    4865        }
    49 
     66        JSString(PassRefPtr<UString::Rep> value, HasOtherOwnerType)
     67            : m_value(value)
     68        {
     69        }
     70       
    5071        const UString& value() const { return m_value; }
    5172
     
    5475
    5576        bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); }
    56         JSValue* getIndex(ExecState* exec, unsigned i)
    57         {
    58             ASSERT(canGetIndex(i));
    59             return new (exec) JSString(m_value.substr(i, 1));
    60         }
     77        JSString* getIndex(ExecState*, unsigned);
    6178
    6279    private:
     
    8198    };
    8299
    83     JSString* jsString(ExecState*, const UString&); // returns empty string if passed null string
    84     JSString* jsString(ExecState*, const char* = ""); // returns empty string if passed 0
     100    inline JSString* jsEmptyString(ExecState* exec)
     101    {
     102        return exec->globalData().smallStrings.emptyString(exec);
     103    }
    85104
    86     // Should be used for strings that are owned by an object that will
    87     // likely outlive the JSValue this makes, such as the parse tree or a
    88     // DOM object that contains a UString
    89     JSString* jsOwnedString(ExecState*, const UString&);
     105    inline JSString* jsSingleCharacterString(ExecState* exec, UChar c)
     106    {
     107        if (c <= 0xFF)
     108            return exec->globalData().smallStrings.singleCharacterString(exec, c);
     109        return new (exec) JSString(UString(&c, 1));
     110    }
     111
     112    inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
     113    {
     114        ASSERT(offset < static_cast<unsigned>(s.size()));
     115        UChar c = s.data()[offset];
     116        if (c <= 0xFF)
     117            return exec->globalData().smallStrings.singleCharacterString(exec, c);
     118        return new (exec) JSString(UString::Rep::create(s.rep(), offset, 1));
     119    }
     120
     121    inline JSString* jsNontrivialString(ExecState* exec, const char* s)
     122    {
     123        ASSERT(s);
     124        ASSERT(s[0]);
     125        ASSERT(s[1]);
     126        return new (exec) JSString(s);
     127    }
     128
     129    inline JSString* jsNontrivialString(ExecState* exec, const UString& s)
     130    {
     131        ASSERT(s.size() > 1);
     132        return new (exec) JSString(s);
     133    }
     134
     135    inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
     136    {
     137        ASSERT(canGetIndex(i));
     138        return jsSingleCharacterSubstring(exec, m_value, i);
     139    }
    90140
    91141    ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    92142    {
    93143        if (propertyName == exec->propertyNames().length) {
    94             slot.setValue(jsNumber(exec, value().size()));
     144            slot.setValue(jsNumber(exec, m_value.size()));
    95145            return true;
    96146        }
     
    99149        unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
    100150        if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) {
    101             slot.setValue(jsString(exec, value().substr(i, 1)));
     151            slot.setValue(jsSingleCharacterSubstring(exec, m_value, i));
    102152            return true;
    103153        }
     
    109159    {
    110160        if (propertyName < static_cast<unsigned>(m_value.size())) {
    111             slot.setValue(jsString(exec, value().substr(propertyName, 1)));
     161            slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName));
    112162            return true;
    113163        }
  • trunk/JavaScriptCore/kjs/NumberPrototype.cpp

    r35807 r36006  
    234234    double x = v->uncheckedGetNumber();
    235235    if (isnan(x))
    236         return jsString(exec, "NaN");
     236        return jsNontrivialString(exec, "NaN");
    237237
    238238    UString s;
     
    340340
    341341    if (isnan(x))
    342         return jsString(exec, "NaN");
     342        return jsNontrivialString(exec, "NaN");
    343343
    344344    if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0
     
    423423                m = m.substr(0, 1) + "." + m.substr(1);
    424424            if (e >= 0)
    425                 return jsString(exec, s + m + "e+" + UString::from(e));
    426             return jsString(exec, s + m + "e-" + UString::from(-e));
     425                return jsNontrivialString(exec, s + m + "e+" + UString::from(e));
     426            return jsNontrivialString(exec, s + m + "e-" + UString::from(-e));
    427427        }
    428428    } else {
     
    438438        return jsString(exec, s + m);
    439439    }
    440     return jsString(exec, s + "0." + charSequence('0', -(e + 1)) + m);
     440    return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m);
    441441}
    442442
  • trunk/JavaScriptCore/kjs/ObjectPrototype.cpp

    r35807 r36006  
    127127JSValue* objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    128128{
    129     return jsString(exec, thisValue->toThisObject(exec)->toString(exec));
     129    return thisValue->toThisJSString(exec);
    130130}
    131131
    132132JSValue* objectProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    133133{
    134     return jsString(exec, "[object " + thisValue->toThisObject(exec)->className() + "]");
     134    return jsNontrivialString(exec, "[object " + thisValue->toThisObject(exec)->className() + "]");
    135135}
    136136
  • trunk/JavaScriptCore/kjs/RegExpConstructor.cpp

    r35807 r36006  
    7272    }
    7373
     74    UString input;
    7475    UString lastInput;
    7576    OwnArrayPtr<int> lastOvector;
     
    107108        length = tmpOvector[1] - tmpOvector[0];
    108109
     110        d->input = s;
    109111        d->lastInput = s;
    110112        d->lastOvector.set(tmpOvector.release());
     
    134136{
    135137    RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
     138    d->input = data->lastInput;
    136139    d->lastInput = data->lastInput;
    137140    d->lastNumSubPatterns = data->lastNumSubPatterns;
     
    159162        int start = d->lastOvector[2 * i];
    160163        if (start >= 0)
    161             JSArray::put(exec, i, jsString(exec, d->lastInput.substr(start, d->lastOvector[2 * i + 1] - start)));
     164            JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start));
    162165    }
    163166    JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector[0]));
    164     JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->lastInput));
     167    JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input));
    165168
    166169    delete d;
     
    175178JSValue* RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
    176179{
    177     if (d->lastOvector && i <= d->lastNumSubPatterns)
    178         return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
    179     return jsString(exec, "");
     180    if (d->lastOvector && i <= d->lastNumSubPatterns) {
     181        int start = d->lastOvector[2 * i];
     182        if (start >= 0)
     183            return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
     184    }
     185    return jsEmptyString(exec);
    180186}
    181187
     
    185191    if (i > 0) {
    186192        ASSERT(d->lastOvector);
    187         return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
    188     }
    189     return jsString(exec, "");
     193        int start = d->lastOvector[2 * i];
     194        if (start >= 0)
     195            return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
     196    }
     197    return jsEmptyString(exec);
    190198}
    191199
     
    193201{
    194202    if (d->lastOvector)
    195         return jsString(exec, d->lastInput.substr(0, d->lastOvector[0]));
    196     return jsString(exec, "");
     203        return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]);
     204    return jsEmptyString(exec);
    197205}
    198206
    199207JSValue* RegExpConstructor::getRightContext(ExecState* exec) const
    200208{
    201     if (d->lastOvector) {
    202         UString s = d->lastInput;
    203         return jsString(exec, s.substr(d->lastOvector[1], s.size() - d->lastOvector[1]));
    204     }
    205     return jsString(exec, "");
     209    if (d->lastOvector)
     210        return jsSubstring(exec, d->lastInput, d->lastOvector[1], d->lastInput.size() - d->lastOvector[1]);
     211    return jsEmptyString(exec);
    206212}
    207213   
     
    233239            return getBackref(exec, 9);
    234240        case Input:
    235             return jsString(exec, d->lastInput);
     241            return jsString(exec, d->input);
    236242        case Multiline:
    237243            return jsBoolean(d->multiline);
     
    248254    }
    249255
    250     return jsString(exec, "");
     256    return jsEmptyString(exec);
    251257}
    252258
     
    260266    switch (token) {
    261267        case Input:
    262             d->lastInput = value->toString(exec);
     268            d->input = value->toString(exec);
    263269            break;
    264270        case Multiline:
     
    318324    // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
    319325    // state (since jsString turns null strings to empty strings).
    320     return d->lastInput;
     326    return d->input;
    321327}
    322328
  • trunk/JavaScriptCore/kjs/RegExpPrototype.cpp

    r35807 r36006  
    102102    if (!thisValue->isObject(&RegExpObject::info)) {
    103103        if (thisValue->isObject(&RegExpPrototype::info))
    104             return jsString(exec, "//");
     104            return jsNontrivialString(exec, "//");
    105105        return throwError(exec, TypeError);
    106106    }
    107107
    108     UString result = "/" + static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().source)->toString(exec) + "/";
     108    UString result = "/" + static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().source)->toString(exec);
     109    result.append('/');
    109110    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().global)->toBoolean(exec))
    110         result += "g";
     111        result.append('g');
    111112    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec))
    112         result += "i";
     113        result.append('i');
    113114    if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean(exec))
    114         result += "m";
    115     return jsString(exec, result);
     115        result.append('m');
     116    return jsNontrivialString(exec, result);
    116117}
    117118
  • trunk/JavaScriptCore/kjs/StringConstructor.cpp

    r35807 r36006  
    2929namespace KJS {
    3030
     31static NEVER_INLINE JSValue* stringFromCharCodeSlowCase(ExecState* exec, const ArgList& args)
     32{
     33    UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar)));
     34    UChar* p = buf;
     35    ArgList::const_iterator end = args.end();
     36    for (ArgList::const_iterator it = args.begin(); it != end; ++it)
     37        *p++ = static_cast<UChar>((*it).jsValue(exec)->toUInt32(exec));
     38    return jsString(exec, UString(buf, p - buf, false));
     39}
     40
    3141static JSValue* stringFromCharCode(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    3242{
    33     UString s;
    34     if (args.size()) {
    35         UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar)));
    36         UChar* p = buf;
    37         ArgList::const_iterator end = args.end();
    38         for (ArgList::const_iterator it = args.begin(); it != end; ++it)
    39             *p++ = static_cast<UChar>((*it).jsValue(exec)->toUInt32(exec));
    40         s = UString(buf, args.size(), false);
    41     } else
    42         s = "";
    43 
    44     return jsString(exec, s);
     43    if (LIKELY(args.size() == 1))
     44        return jsSingleCharacterString(exec, args.at(exec, 0)->toUInt32(exec));
     45    return stringFromCharCodeSlowCase(exec, args);
    4546}
    4647
     
    7980{
    8081    if (args.isEmpty())
    81         return jsString(exec, "");
     82        return jsEmptyString(exec);
    8283    return jsString(exec, args.at(exec, 0)->toString(exec));
    8384}
  • trunk/JavaScriptCore/kjs/StringObject.cpp

    r35807 r36006  
    3333    : JSWrapperObject(prototype)
    3434{
    35     setInternalValue(jsString(exec, ""));
     35    setInternalValue(jsEmptyString(exec));
    3636}
    3737
  • trunk/JavaScriptCore/kjs/StringPrototype.cpp

    r35807 r36006  
    251251                        args.append(jsUndefined());
    252252                    else
    253                         args.append(jsString(exec, source.substr(matchStart, matchLen)));
     253                        args.append(jsSubstring(exec, source, matchStart, matchLen));
    254254                }
    255255
     
    293293    if (callType != CallTypeNone) {
    294294        ArgList args;
    295         args.append(jsString(exec, source.substr(matchPos, matchLen)));
     295        args.append(jsSubstring(exec, source, matchPos, matchLen));
    296296        args.append(jsNumber(exec, matchPos));
    297297        args.append(sourceVal);
     
    319319{
    320320    UString s = thisValue->toThisString(exec);
    321     int len = s.size();
    322 
    323     UString u;
    324     JSValue* a0 = args.at(exec, 0);
     321    unsigned len = s.size();
     322    JSValue* a0 = args.at(exec, 0);
     323    if (JSImmediate::isNumber(a0)) {
     324        uint32_t i;
     325        if (JSImmediate::getUInt32(a0, i) && i < len)
     326            return jsSingleCharacterSubstring(exec, s, i);
     327        return jsEmptyString(exec);
     328    }
    325329    double dpos = a0->toInteger(exec);
    326330    if (dpos >= 0 && dpos < len)
    327         u = s.substr(static_cast<int>(dpos), 1);
    328     else
    329         u = "";
    330     return jsString(exec, u);
     331        return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos));
     332    return jsEmptyString(exec);
    331333}
    332334
     
    334336{
    335337    UString s = thisValue->toThisString(exec);
    336     int len = s.size();
    337 
    338     JSValue* result = 0;
    339 
    340     JSValue* a0 = args.at(exec, 0);
     338    unsigned len = s.size();
     339    JSValue* a0 = args.at(exec, 0);
     340    if (JSImmediate::isNumber(a0)) {
     341        uint32_t i;
     342        if (JSImmediate::getUInt32(a0, i) && i < len)
     343            return jsNumber(exec, s.data()[i]);
     344        return jsNaN(exec);
     345    }
    341346    double dpos = a0->toInteger(exec);
    342347    if (dpos >= 0 && dpos < len)
    343         result = jsNumber(exec, s[static_cast<int>(dpos)]);
    344     else
    345         result = jsNaN(exec);
    346     return result;
     348        return jsNumber(exec, s[static_cast<int>(dpos)]);
     349    return jsNaN(exec);
    347350}
    348351
     
    424427    int lastIndex = 0;
    425428    while (pos >= 0) {
    426         list.append(jsString(exec, u.substr(pos, matchLength)));
     429        list.append(jsSubstring(exec, u, pos, matchLength));
    427430        lastIndex = pos;
    428431        pos += matchLength == 0 ? 1 : matchLength;
     
    484487        if (to > len)
    485488            to = len;
    486         return jsString(exec, s.substr(static_cast<int>(from), static_cast<int>(to - from)));
    487     }
    488 
    489     return jsString(exec, "");
     489        return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
     490    }
     491
     492    return jsEmptyString(exec);
    490493}
    491494
     
    497500    JSValue* a1 = args.at(exec, 1);
    498501
    499     JSObject* res = constructEmptyArray(exec);
    500     JSValue* result = res;
    501     UString u = s;
    502     int pos;
    503     int i = 0;
     502    JSArray* result = constructEmptyArray(exec);
     503    unsigned i = 0;
    504504    int p0 = 0;
    505     uint32_t limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);
     505    unsigned limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);
    506506    if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpObject::info)) {
    507507        RegExp *reg = static_cast<RegExpObject *>(a0)->regExp();
    508         if (u.isEmpty() && reg->match(u, 0) >= 0) {
     508        if (s.isEmpty() && reg->match(s, 0) >= 0) {
    509509            // empty string matched by regexp -> empty array
    510             res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));
    511510            return result;
    512511        }
    513         pos = 0;
    514         while (static_cast<uint32_t>(i) != limit && pos < u.size()) {
     512        int pos = 0;
     513        while (i != limit && pos < s.size()) {
    515514            OwnArrayPtr<int> ovector;
    516             int mpos = reg->match(u, pos, &ovector);
     515            int mpos = reg->match(s, pos, &ovector);
    517516            if (mpos < 0)
    518517                break;
     
    520519            pos = mpos + (mlen == 0 ? 1 : mlen);
    521520            if (mpos != p0 || mlen) {
    522                 res->put(exec,i, jsString(exec, u.substr(p0, mpos - p0)));
     521                result->put(exec, i++, jsSubstring(exec, s, p0, mpos - p0));
    523522                p0 = mpos + mlen;
    524                 i++;
    525523            }
    526524            for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) {
    527525                int spos = ovector[si * 2];
    528526                if (spos < 0)
    529                     res->put(exec, i++, jsUndefined());
     527                    result->put(exec, i++, jsUndefined());
    530528                else
    531                     res->put(exec, i++, jsString(exec, u.substr(spos, ovector[si * 2 + 1] - spos)));
     529                    result->put(exec, i++, jsSubstring(exec, s, spos, ovector[si * 2 + 1] - spos));
    532530            }
    533531        }
     
    535533        UString u2 = a0->toString(exec);
    536534        if (u2.isEmpty()) {
    537             if (u.isEmpty()) {
     535            if (s.isEmpty()) {
    538536                // empty separator matches empty string -> empty array
    539                 res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));
    540537                return result;
    541             } else {
    542                 while (static_cast<uint32_t>(i) != limit && i < u.size() - 1)
    543                     res->put(exec, i++, jsString(exec, u.substr(p0++, 1)));
    544538            }
     539            while (i != limit && p0 < s.size() - 1)
     540                result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++));
    545541        } else {
    546             while (static_cast<uint32_t>(i) != limit && (pos = u.find(u2, p0)) >= 0) {
    547                 res->put(exec, i, jsString(exec, u.substr(p0, pos - p0)));
     542            int pos;
     543            while (i != limit && (pos = s.find(u2, p0)) >= 0) {
     544                result->put(exec, i++, jsSubstring(exec, s, p0, pos - p0));
    548545                p0 = pos + u2.size();
    549                 i++;
    550546            }
    551547        }
    552548    }
    553549
    554     // add remaining string, if any
    555     if (static_cast<uint32_t>(i) != limit)
    556         res->put(exec, i++, jsString(exec, u.substr(p0)));
    557     res->put(exec, exec->propertyNames().length, jsNumber(exec, i));
     550    // add remaining string
     551    if (i != limit)
     552        result->put(exec, i++, jsSubstring(exec, s, p0, s.size() - p0));
     553
    558554    return result;
    559555}
     
    570566    double length = a1->isUndefined() ? len : a1->toInteger(exec);
    571567    if (start >= len)
    572         return jsString(exec, "");
     568        return jsEmptyString(exec);
    573569    if (length < 0)
    574         return jsString(exec, "");
     570        return jsEmptyString(exec);
    575571    if (start < 0) {
    576572        start += len;
     
    580576    if (length > len)
    581577        length = len;
    582     return jsString(exec, s.substr(static_cast<int>(start), static_cast<int>(length)));
     578    return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length));
    583579}
    584580
     
    612608        start = temp;
    613609    }
    614     return jsString(exec, s.substr(static_cast<int>(start), (static_cast<int>(end) - static_cast<int>(start))));
     610    return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(end) - static_cast<unsigned>(start));
    615611}
    616612
  • trunk/JavaScriptCore/kjs/collector.cpp

    r35853 r36006  
    970970        ArgList::markLists(*m_markListSet);
    971971    m_globalData->machine->registerFile().markCallFrames(this);
     972    m_globalData->smallStrings.mark();
    972973
    973974    JAVASCRIPTCORE_GC_MARKED();
  • trunk/JavaScriptCore/kjs/ustring.cpp

    r35691 r36006  
    395395
    396396// put these early so they can be inlined
    397 inline size_t UString::expandedSize(size_t size, size_t otherSize) const
     397inline size_t UString::expandedSize(size_t size, size_t otherSize)
    398398{
    399399    // Do the size calculation in two parts, returning overflowIndicator if
     
    432432        if (!r->buf) {
    433433            r->buf = oldBuf;
    434             m_rep = &Rep::null;
     434            makeNull();
    435435            return;
    436436        }
     
    455455        UChar* newBuf = allocChars(newCapacity);
    456456        if (!newBuf) {
    457             m_rep = &Rep::null;
     457            makeNull();
    458458            return;
    459459        }
     
    485485    UChar* d = allocChars(length);
    486486    if (!d)
    487         m_rep = &Rep::null;
     487        makeNull();
    488488    else {
    489489        for (size_t i = 0; i < length; i++)
     
    519519}
    520520
    521 
    522 UString::UString(const UString& a, const UString& b)
    523 {
    524     a.rep()->checkConsistency();
    525     b.rep()->checkConsistency();
    526 
    527     int aSize = a.size();
    528     int aOffset = a.m_rep->offset;
    529     int bSize = b.size();
    530     int bOffset = b.m_rep->offset;
     521PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b)
     522{
     523    a->checkConsistency();
     524    b->checkConsistency();
     525
     526    int aSize = a->size();
     527    int aOffset = a->offset;
     528    int bSize = b->size();
     529    int bOffset = b->offset;
    531530    int length = aSize + bSize;
    532531
    533532    // possible cases:
    534533
    535     if (aSize == 0) {
    536         // a is empty
    537         m_rep = b.m_rep;
    538     } else if (bSize == 0) {
    539         // b is empty
    540         m_rep = a.m_rep;
    541     } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize &&
    542                (-bOffset != b.usedPreCapacity() || aSize >= bSize)) {
     534    // a is empty
     535    if (aSize == 0)
     536        return b;
     537    // b is empty
     538    if (bSize == 0)
     539        return a;
     540
     541    if (bSize == 1 && aOffset + aSize == a->baseString->usedCapacity && aOffset + length <= a->baseString->capacity) {
     542        // b is a single character (common fast case)
     543        a->baseString->usedCapacity = aOffset + length;
     544        a->data()[aSize] = b->data()[0];
     545        return UString::Rep::create(a, 0, length);
     546    }
     547
     548    if (aOffset + aSize == a->baseString->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize &&
     549               (-bOffset != b->baseString->usedPreCapacity || aSize >= bSize)) {
    543550        // - a reaches the end of its buffer so it qualifies for shared append
    544551        // - also, it's at least a quarter the length of b - appending to a much shorter
     
    547554        UString x(a);
    548555        x.expandCapacity(aOffset + length);
    549         if (a.data() && x.data()) {
    550             memcpy(const_cast<UChar*>(a.data() + aSize), b.data(), bSize * sizeof(UChar));
    551             m_rep = Rep::create(a.m_rep, 0, length);
    552         } else
    553             m_rep = &Rep::null;
    554     } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize  && 4 * bSize >= aSize) {
     556        if (!a->data() || !x.data())
     557            return 0;
     558        memcpy(a->data() + aSize, b->data(), bSize * sizeof(UChar));
     559        PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length);
     560
     561        a->checkConsistency();
     562        b->checkConsistency();
     563        result->checkConsistency();
     564
     565        return result;
     566    }
     567
     568    if (-bOffset == b->baseString->usedPreCapacity && bSize >= minShareSize  && 4 * bSize >= aSize) {
    555569        // - b reaches the beginning of its buffer so it qualifies for shared prepend
    556570        // - also, it's at least a quarter the length of a - prepending to a much shorter
     
    558572        UString y(b);
    559573        y.expandPreCapacity(-bOffset + aSize);
    560         if (b.data() && y.data()) {
    561             memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar));
    562             m_rep = Rep::create(b.m_rep, -aSize, length);
    563         } else
    564             m_rep = &Rep::null;
    565     } else {
    566         // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
    567         size_t newCapacity = expandedSize(length, 0);
    568         UChar* d = allocChars(newCapacity);
    569         if (!d)
    570             m_rep = &Rep::null;
    571         else {
    572             memcpy(d, a.data(), aSize * sizeof(UChar));
    573             memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
    574             m_rep = Rep::create(d, length);
    575             m_rep->capacity = newCapacity;
    576         }
    577     }
    578     a.rep()->checkConsistency();
    579     b.rep()->checkConsistency();
    580     m_rep->checkConsistency();
     574        if (!b->data() || !y.data())
     575            return 0;
     576        memcpy(b->data() - aSize, a->data(), aSize * sizeof(UChar));
     577        PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length);
     578
     579        a->checkConsistency();
     580        b->checkConsistency();
     581        result->checkConsistency();
     582
     583        return result;
     584    }
     585
     586    // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
     587    size_t newCapacity = UString::expandedSize(length, 0);
     588    UChar* d = allocChars(newCapacity);
     589    if (!d)
     590        return 0;
     591    memcpy(d, a->data(), aSize * sizeof(UChar));
     592    memcpy(d + aSize, b->data(), bSize * sizeof(UChar));
     593    PassRefPtr<UString::Rep> result = UString::Rep::create(d, length);
     594    result->capacity = newCapacity;
     595
     596    a->checkConsistency();
     597    b->checkConsistency();
     598    result->checkConsistency();
     599
     600    return result;
    581601}
    582602
     
    807827        UChar* d = allocChars(newCapacity);
    808828        if (!d)
    809             m_rep = &Rep::null;
     829            makeNull();
    810830        else {
    811831            memcpy(d, data(), thisSize * sizeof(UChar));
     
    856876        UChar* d = allocChars(newCapacity);
    857877        if (!d)
    858             m_rep = &Rep::null;
     878            makeNull();
    859879        else {
    860880            memcpy(d, data(), thisSize * sizeof(UChar));
     
    909929        UChar* d = allocChars(newCapacity);
    910930        if (!d)
    911             m_rep = &Rep::null;
     931            makeNull();
    912932        else {
    913933            memcpy(d, data(), thisSize * sizeof(UChar));
     
    937957        UChar* d = allocChars(newCapacity);
    938958        if (!d)
    939             m_rep = &Rep::null;
     959            makeNull();
    940960        else {
    941961            d[0] = c;
     
    965985        UChar* d = allocChars(newCapacity);
    966986        if (!d)
    967             m_rep = &Rep::null;
     987            makeNull();
    968988        else {
    969989            memcpy(d, data(), length * sizeof(UChar));
     
    10431063        d = allocChars(l);
    10441064        if (!d) {
    1045             m_rep = &Rep::null;
     1065            makeNull();
    10461066            return *this;
    10471067        }
     
    10761096double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
    10771097{
    1078     double d;
     1098    if (size() == 1) {
     1099        UChar c = data()[0];
     1100        if (isASCIIDigit(c))
     1101            return c - '0';
     1102        if (isASCIISpace(c) && tolerateEmptyString)
     1103            return 0;
     1104        return NaN;
     1105    }
    10791106
    10801107    // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
     
    10921119    if (*c == '\0')
    10931120        return tolerateEmptyString ? 0.0 : NaN;
     1121
     1122    double d;
    10941123
    10951124    // hex number ?
     
    13351364bool operator==(const UString& s1, const UString& s2)
    13361365{
    1337     if (s1.m_rep->len != s2.m_rep->len)
    1338         return false;
    1339 
    1340     return (memcmp(s1.m_rep->data(), s2.m_rep->data(), s1.m_rep->len * sizeof(UChar)) == 0);
     1366    int size = s1.size();
     1367    switch (size) {
     1368        case 0:
     1369            return !s2.size();
     1370        case 1:
     1371            return s2.size() == 1 && s1.data()[0] == s2.data()[0];
     1372        default:
     1373            return s2.size() == size && memcmp(s1.data(), s2.data(), size * sizeof(UChar)) == 0;
     1374    }
    13411375}
    13421376
     
    14491483}
    14501484
     1485// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
     1486NEVER_INLINE void UString::makeNull()
     1487{
     1488    m_rep = &Rep::null;
     1489}
     1490
     1491// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
     1492NEVER_INLINE UString::Rep* UString::nullRep()
     1493{
     1494    return &Rep::null;
     1495}
     1496
    14511497} // namespace KJS
  • trunk/JavaScriptCore/kjs/ustring.h

    r35458 r36006  
    7272
    7373    class UString {
    74     friend bool operator==(const UString&, const UString&);
    75 
    7674    public:
    7775        struct Rep {
     
    140138
    141139        UString(const Vector<UChar>& buffer);
    142 
    143         // Concatenation constructor. Makes operator+ more efficient.
    144         UString(const UString&, const UString&);
    145140
    146141        ~UString()
     
    235230
    236231        Rep* rep() const { return m_rep.get(); }
     232        static Rep* nullRep();
    237233
    238234        UString(PassRefPtr<Rep> r)
     
    245241
    246242    private:
    247         size_t expandedSize(size_t size, size_t otherSize) const;
     243        static size_t expandedSize(size_t size, size_t otherSize);
    248244        int usedCapacity() const;
    249245        int usedPreCapacity() const;
    250246        void expandCapacity(int requiredLength);
    251247        void expandPreCapacity(int requiredPreCap);
     248        void makeNull();
    252249
    253250        RefPtr<Rep> m_rep;
    254     };
    255 
    256     bool operator==(const UString& s1, const UString& s2);
     251
     252        friend bool operator==(const UString&, const UString&);
     253        friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory
     254    };
    257255
    258256    inline bool operator!=(const UString& s1, const UString& s2)
     
    281279    }
    282280
    283     bool operator==(const CString& s1, const CString& s2);
     281    bool operator==(const CString&, const CString&);
    284282
    285283    inline UString operator+(const UString& s1, const UString& s2)
    286284    {
    287         return UString(s1, s2);
     285        RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep());
     286        return UString(result ? result.release() : UString::nullRep());
    288287    }
    289288
  • trunk/LayoutTests/ChangeLog

    r35994 r36006  
     12008-08-30  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Maciej.
     4
     5        - updated incorrect results that reflected a bug in the RegExp object
     6
     7        * fast/js/regexp-caching-expected.txt: Updated results to
     8        correctly show that $1 through $9, lastMatch, lastParen,
     9        leftContext, and rightContext are left alone both when
     10        a program changes the value of RegExp.input and when it
     11        performs an unsuccessful match. The new results match
     12        Gecko behavior (I tested both Firefox 2 and 3).
     13
    1142008-08-29  Eric Carlson  <eric.carlson@apple.com>
    215
  • trunk/LayoutTests/fast/js/regexp-caching-expected.txt

    r20023 r36006  
    4242
    4343Properties of RegExp after /(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)/.exec(XXX):
    44 $1: {}
    45 $2: {}
    46 $3: {}
    47 $4: {}
    48 $5: {}
    49 $6: {}
    50 $7: {}
    51 $8: {}
    52 $9: {}
     44$1: {1}
     45$2: {2}
     46$3: {3}
     47$4: {4}
     48$5: {5}
     49$6: {6}
     50$7: {7}
     51$8: {8}
     52$9: {9}
    5353input: {0}
    54 lastMatch: {}
    55 lastParen: {}
    56 leftContext: {0}
     54lastMatch: {1234567890}
     55lastParen: {0}
     56leftContext: {<}
    5757multiline: {true}
    58 rightContext: {}
     58rightContext: {>}
    5959
    6060---------- [Cleared RegExp values] ----------
  • trunk/WebCore/ChangeLog

    r36002 r36006  
     12008-08-30  Darin Adler  <darin@apple.com>
     2
     3        Reviewed by Maciej.
     4
     5        - adopt some new JavaScriptCore functions where appropriate
     6
     7        * bindings/js/JSDOMWindowBase.cpp:
     8        (WebCore::windowProtoFuncAToB): Adopted jsEmptyString.
     9        (WebCore::windowProtoFuncBToA): Ditto.
     10        * bindings/js/JSEventListener.cpp:
     11        (WebCore::JSLazyEventListener::eventParameterName): Adopted
     12        jsNontrivialString.
     13        * bindings/js/JSSVGLazyEventListener.cpp:
     14        (WebCore::JSSVGLazyEventListener::eventParameterName): Ditto.
     15
    1162008-08-29  Brady Eidson  <beidson@apple.com>
    217
  • trunk/WebCore/bindings/js/JSDOMWindowBase.cpp

    r35964 r36006  
    939939    JSValue* v = args.at(exec, 0);
    940940    if (v->isNull())
    941         return jsString(exec);
     941        return jsEmptyString(exec);
    942942
    943943    UString s = v->toString(exec);
     
    971971    JSValue* v = args.at(exec, 0);
    972972    if (v->isNull())
    973         return jsString(exec);
     973        return jsEmptyString(exec);
    974974
    975975    UString s = v->toString(exec);
  • trunk/WebCore/bindings/js/JSEventListener.cpp

    r35853 r36006  
    245245JSValue* JSLazyEventListener::eventParameterName() const
    246246{
    247     static ProtectedPtr<JSValue> eventString = jsString(window()->globalExec(), "event");
     247    static ProtectedPtr<JSValue> eventString = jsNontrivialString(window()->globalExec(), "event");
    248248    return eventString.get();
    249249}
  • trunk/WebCore/bindings/js/JSSVGLazyEventListener.cpp

    r34659 r36006  
    3838JSValue* JSSVGLazyEventListener::eventParameterName() const
    3939{
    40     static ProtectedPtr<JSValue> eventString = jsString(window()->globalExec(), "evt");
     40    static ProtectedPtr<JSValue> eventString = jsNontrivialString(window()->globalExec(), "evt");
    4141    return eventString.get();
    4242}
Note: See TracChangeset for help on using the changeset viewer.