Changeset 36006 in webkit
- Timestamp:
- Aug 30, 2008, 11:58:07 PM (17 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 33 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/API/JSObjectRef.cpp
r35900 r36006 118 118 ArgList args; 119 119 for (unsigned i = 0; i < parameterCount; i++) 120 args.append(jsString(exec, UString(parameterNames[i]->ustring())));120 args.append(jsString(exec, parameterNames[i]->ustring())); 121 121 args.append(jsString(exec, body->ustring())); 122 122 -
trunk/JavaScriptCore/ChangeLog
r36004 r36006 1 2008-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 1 193 2008-08-29 Anders Carlsson <andersca@apple.com> 2 194 -
trunk/JavaScriptCore/GNUmakefile.am
r35985 r36006 175 175 JavaScriptCore/kjs/ScopeChain.h \ 176 176 JavaScriptCore/kjs/ScopeChainMark.h \ 177 JavaScriptCore/kjs/SmallStrings.h \ 177 178 JavaScriptCore/kjs/SourceProvider.h \ 178 179 JavaScriptCore/kjs/SourceRange.h \ … … 344 345 JavaScriptCore/kjs/RegExpPrototype.cpp \ 345 346 JavaScriptCore/kjs/ScopeChain.cpp \ 347 JavaScriptCore/kjs/SmallStrings.cpp \ 346 348 JavaScriptCore/kjs/StringConstructor.cpp \ 347 349 JavaScriptCore/kjs/StringObject.cpp \ -
trunk/JavaScriptCore/JavaScriptCore.exp
r35930 r36006 114 114 __ZN3KJS12SamplingTool4stopEv 115 115 __ZN3KJS12SamplingTool5startEj 116 __ZN3KJS12SmallStrings17createEmptyStringEPNS_9ExecStateE 116 117 __ZN3KJS12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE 117 118 __ZN3KJS12StringObject14toThisJSStringEPNS_9ExecStateE … … 233 234 __ZN3KJS8Profiler21didFinishAllExecutionEPNS_9ExecStateE 234 235 __ZN3KJS8Profiler8profilerEv 235 __ZN3KJS8jsStringEPNS_9ExecStateEPKc236 236 __ZN3KJS8jsStringEPNS_9ExecStateERKNS_7UStringE 237 237 __ZN3KJS9constructEPNS_9ExecStateEPNS_7JSValueENS_13ConstructTypeERKNS_13ConstructDataERKNS_7ArgListE … … 335 335 __ZTVN3KJS16JSVariableObjectE 336 336 __ZTVN3KJS8JSObjectE 337 __ZTVN3KJS8JSStringE 337 338 _jscore_fastmalloc_introspection 338 339 _kJSClassDefinitionEmpty -
trunk/JavaScriptCore/JavaScriptCore.pri
r35853 r36006 132 132 kjs/RegExpPrototype.cpp \ 133 133 kjs/ScopeChain.cpp \ 134 kjs/SmallStrings.cpp \ 134 135 kjs/StringConstructor.cpp \ 135 136 kjs/StringObject.cpp \ -
trunk/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
r35853 r36006 838 838 </File> 839 839 <File 840 RelativePath="..\..\kjs\simple_number.h" 840 RelativePath="..\..\kjs\SmallStrings.h" 841 > 842 </File> 843 <File 844 RelativePath="..\..\kjs\SmallStrings.cpp" 841 845 > 842 846 </File> -
trunk/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r35984 r36006 68 68 14E0FF120DBAAED00007C0AB /* Machine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 149B15E70D81F986009CB8C7 /* Machine.cpp */; settings = {COMPILER_FLAGS = "-fno-tree-pre"; }; }; 69 69 5D53726F0E1C54880021E549 /* Tracing.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53726E0E1C54880021E549 /* Tracing.h */; }; 70 5D53727E0E1C55EC0021E549 /* TracingDtrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D53727D0E1C55EC0021E549 /* TracingDtrace.h */; };71 70 5D5D8AB60E0D0A7200F9C692 /* jsc in Copy Into Framework */ = {isa = PBXBuildFile; fileRef = 932F5BE10822A1C700736975 /* jsc */; }; 72 71 5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; … … 89 88 932F5BDD0822A1C700736975 /* Shell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45E12D8806A49B0F00E9DF84 /* Shell.cpp */; }; 90 89 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 */; }; 91 92 937013480CA97E0E00FA14D3 /* pcre_ucp_searchfuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 937013470CA97E0E00FA14D3 /* pcre_ucp_searchfuncs.cpp */; settings = {COMPILER_FLAGS = "-Wno-sign-compare"; }; }; 92 93 93E26BD408B1514100F85226 /* pcre_xclass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E26BD308B1514100F85226 /* pcre_xclass.cpp */; }; … … 577 578 932F5BD90822A1C700736975 /* JavaScriptCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 578 579 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>"; }; 579 582 933A3499038AE7C6008635CE /* grammar.y */ = {isa = PBXFileReference; explicitFileType = sourcecode.yacc; fileEncoding = 4; indentWidth = 4; path = grammar.y; sourceTree = "<group>"; tabWidth = 8; }; 580 583 933A349A038AE7C6008635CE /* identifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = identifier.h; sourceTree = "<group>"; tabWidth = 8; }; … … 1244 1247 9374D3A7038D9D74008635CE /* ScopeChain.h */, 1245 1248 7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */, 1249 93303FE80E6A72B500786E6A /* SmallStrings.cpp */, 1250 93303FEA0E6A72C000786E6A /* SmallStrings.h */, 1246 1251 65E866ED0DD59AFA00A2B2A1 /* SourceProvider.h */, 1247 1252 65E866EE0DD59AFA00A2B2A1 /* SourceRange.h */, … … 1520 1525 95CD45770E1C4FDD0085358E /* ProfileGenerator.h in Headers */, 1521 1526 5D53726F0E1C54880021E549 /* Tracing.h in Headers */, 1522 5D53727E0E1C55EC0021E549 /* TracingDtrace.h in Headers */,1523 1527 BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */, 1524 1528 BC3046070E1F497F003232CF /* Error.h in Headers */, … … 1534 1538 E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */, 1535 1539 9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */, 1540 933040040E6A749400786E6A /* SmallStrings.h in Headers */, 1536 1541 ); 1537 1542 runOnlyForDeploymentPostprocessing = 0; … … 1840 1845 E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */, 1841 1846 95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */, 1847 9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */, 1842 1848 ); 1843 1849 runOnlyForDeploymentPostprocessing = 0; -
trunk/JavaScriptCore/JavaScriptCoreSources.bkl
r35853 r36006 118 118 kjs/RegExpPrototype.cpp 119 119 kjs/ScopeChain.cpp 120 kjs/SmallStrings.cpp 120 121 kjs/StringConstructor.cpp 121 122 kjs/StringObject.cpp -
trunk/JavaScriptCore/VM/Machine.cpp
r36004 r36006 192 192 193 193 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) 196 196 return throwOutOfMemoryError(exec); 197 return jsString(exec, value );197 return jsString(exec, value.release()); 198 198 } 199 199 … … 218 218 219 219 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) 222 222 return throwOutOfMemoryError(exec); 223 return jsString(exec, value );223 return jsString(exec, value.release()); 224 224 } 225 225 … … 231 231 { 232 232 if (v->isUndefined()) 233 return js String(exec, "undefined");233 return jsNontrivialString(exec, "undefined"); 234 234 if (v->isBoolean()) 235 return js String(exec, "boolean");235 return jsNontrivialString(exec, "boolean"); 236 236 if (v->isNumber()) 237 return js String(exec, "number");237 return jsNontrivialString(exec, "number"); 238 238 if (v->isString()) 239 return js String(exec, "string");239 return jsNontrivialString(exec, "string"); 240 240 if (v->isObject()) { 241 241 // Return "undefined" for objects that should be treated 242 242 // as null when doing comparisons. 243 243 if (static_cast<JSObject*>(v)->masqueradeAsUndefined()) 244 return js String(exec, "undefined");244 return jsNontrivialString(exec, "undefined"); 245 245 CallData callData; 246 246 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone) 247 return js String(exec, "function");248 } 249 return js String(exec, "object");247 return jsNontrivialString(exec, "function"); 248 } 249 return jsNontrivialString(exec, "object"); 250 250 } 251 251 -
trunk/JavaScriptCore/kjs/ArrayPrototype.cpp
r35807 r36006 127 127 Vector<UChar, 256> strBuffer; 128 128 if (alreadyVisited) 129 return js String(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.129 return jsEmptyString(exec); // return an empty string, avoiding infinite recursion. 130 130 131 131 unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); … … 171 171 Vector<UChar, 256> strBuffer; 172 172 if (alreadyVisited) 173 return js String(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.173 return jsEmptyString(exec); // return an empty string, avoding infinite recursion. 174 174 175 175 unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec); … … 221 221 Vector<UChar, 256> strBuffer; 222 222 if (alreadyVisited) 223 return js String(exec, UString(0, 0)); // return an empty string, avoding infinite recursion.223 return jsEmptyString(exec); // return an empty string, avoding infinite recursion. 224 224 225 225 UChar comma = ','; -
trunk/JavaScriptCore/kjs/BooleanPrototype.cpp
r35807 r36006 55 55 { 56 56 if (thisValue == jsBoolean(false)) 57 return js String(exec, "false");57 return jsNontrivialString(exec, "false"); 58 58 59 59 if (thisValue == jsBoolean(true)) 60 return js String(exec, "true");60 return jsNontrivialString(exec, "true"); 61 61 62 62 if (!thisValue->isObject(&BooleanObject::info)) … … 64 64 65 65 if (static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(false)) 66 return js String(exec, "false");66 return jsNontrivialString(exec, "false"); 67 67 68 68 ASSERT(static_cast<BooleanObject*>(thisValue)->internalValue() == jsBoolean(true)); 69 return js String(exec, "true");69 return jsNontrivialString(exec, "true"); 70 70 } 71 71 -
trunk/JavaScriptCore/kjs/DateConstructor.cpp
r35807 r36006 125 125 getLocalTime(&localTime, &localTM); 126 126 GregorianDateTime ts(localTM); 127 return js String(exec, formatDate(ts) + " " + formatTime(ts, false));127 return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts, false)); 128 128 } 129 129 -
trunk/JavaScriptCore/kjs/DatePrototype.cpp
r35807 r36006 195 195 196 196 if (ret == 0) 197 return js String(exec, "");197 return jsEmptyString(exec); 198 198 199 199 // Copy original into the buffer … … 209 209 } 210 210 211 return js String(exec, timebuffer);211 return jsNontrivialString(exec, timebuffer); 212 212 } 213 213 … … 370 370 double milli = thisDateObj->internalNumber(); 371 371 if (isnan(milli)) 372 return js String(exec, "Invalid Date");373 374 GregorianDateTime t; 375 thisDateObj->msToGregorianDateTime(milli, utc, t); 376 return js String(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)); 377 377 } 378 378 … … 387 387 double milli = thisDateObj->internalNumber(); 388 388 if (isnan(milli)) 389 return js String(exec, "Invalid Date");390 391 GregorianDateTime t; 392 thisDateObj->msToGregorianDateTime(milli, utc, t); 393 return js String(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)); 394 394 } 395 395 … … 404 404 double milli = thisDateObj->internalNumber(); 405 405 if (isnan(milli)) 406 return js String(exec, "Invalid Date");407 408 GregorianDateTime t; 409 thisDateObj->msToGregorianDateTime(milli, utc, t); 410 return js String(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)); 411 411 } 412 412 … … 421 421 double milli = thisDateObj->internalNumber(); 422 422 if (isnan(milli)) 423 return js String(exec, "Invalid Date");424 425 GregorianDateTime t; 426 thisDateObj->msToGregorianDateTime(milli, utc, t); 427 return js String(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)); 428 428 } 429 429 … … 436 436 double milli = thisDateObj->internalNumber(); 437 437 if (isnan(milli)) 438 return js String(exec, "Invalid Date");438 return jsNontrivialString(exec, "Invalid Date"); 439 439 440 440 #if PLATFORM(MAC) 441 441 double secs = floor(milli / msPerSecond); 442 return js String(exec, formatLocaleDate(exec, secs, true, true, args));442 return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, true, args)); 443 443 #else 444 444 UNUSED_PARAM(args); … … 460 460 double milli = thisDateObj->internalNumber(); 461 461 if (isnan(milli)) 462 return js String(exec, "Invalid Date");462 return jsNontrivialString(exec, "Invalid Date"); 463 463 464 464 #if PLATFORM(MAC) 465 465 double secs = floor(milli / msPerSecond); 466 return js String(exec, formatLocaleDate(exec, secs, true, false, args));466 return jsNontrivialString(exec, formatLocaleDate(exec, secs, true, false, args)); 467 467 #else 468 468 UNUSED_PARAM(args); … … 484 484 double milli = thisDateObj->internalNumber(); 485 485 if (isnan(milli)) 486 return js String(exec, "Invalid Date");486 return jsNontrivialString(exec, "Invalid Date"); 487 487 488 488 #if PLATFORM(MAC) 489 489 double secs = floor(milli / msPerSecond); 490 return js String(exec, formatLocaleDate(exec, secs, false, true, args));490 return jsNontrivialString(exec, formatLocaleDate(exec, secs, false, true, args)); 491 491 #else 492 492 UNUSED_PARAM(args); … … 570 570 double milli = thisDateObj->internalNumber(); 571 571 if (isnan(milli)) 572 return js String(exec, "Invalid Date");573 574 GregorianDateTime t; 575 thisDateObj->msToGregorianDateTime(milli, utc, t); 576 return js String(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)); 577 577 } 578 578 -
trunk/JavaScriptCore/kjs/ErrorPrototype.cpp
r35807 r36006 40 40 // The constructor will be added later in ErrorConstructor's constructor 41 41 42 putDirect(exec->propertyNames().name, js String(exec, "Error"), DontEnum);43 putDirect(exec->propertyNames().message, js String(exec, "Unknown error"), DontEnum);42 putDirect(exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum); 43 putDirect(exec->propertyNames().message, jsNontrivialString(exec, "Unknown error"), DontEnum); 44 44 45 45 putDirectFunction(exec, new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum); … … 63 63 } 64 64 65 return js String(exec, s);65 return jsNontrivialString(exec, s); 66 66 } 67 67 -
trunk/JavaScriptCore/kjs/JSGlobalData.h
r35853 r36006 35 35 #include <wtf/HashSet.h> 36 36 #include <wtf/RefCounted.h> 37 #include "SmallStrings.h" 37 38 38 39 struct OpaqueJSClass; … … 76 77 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. 77 78 79 SmallStrings smallStrings; 80 78 81 HashMap<OpaqueJSClass*, OpaqueJSClassContextData*>* opaqueJSClassData; 79 82 -
trunk/JavaScriptCore/kjs/JSString.cpp
r35830 r36006 116 116 } 117 117 118 JSString* jsString(ExecState* exec, const char* s)119 {120 return new (exec) JSString(s ? s : "");121 }122 123 118 JSString* jsString(ExecState* exec, const UString& s) 124 119 { 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 131 JSString* 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)); 126 144 } 127 145 128 146 JSString* jsOwnedString(ExecState* exec, const UString& s) 129 147 { 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); 131 157 } 132 158 -
trunk/JavaScriptCore/kjs/JSString.h
r35900 r36006 26 26 #include "CommonIdentifiers.h" 27 27 #include "ExecState.h" 28 #include "JSCell.h"29 28 #include "JSNumberCell.h" 30 29 #include "PropertySlot.h" 31 30 #include "identifier.h" 32 #include "ustring.h"33 31 34 32 namespace 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&); 35 52 36 53 class JSString : public JSCell { … … 47 64 { 48 65 } 49 66 JSString(PassRefPtr<UString::Rep> value, HasOtherOwnerType) 67 : m_value(value) 68 { 69 } 70 50 71 const UString& value() const { return m_value; } 51 72 … … 54 75 55 76 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); 61 78 62 79 private: … … 81 98 }; 82 99 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 } 85 104 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 } 90 140 91 141 ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 92 142 { 93 143 if (propertyName == exec->propertyNames().length) { 94 slot.setValue(jsNumber(exec, value().size()));144 slot.setValue(jsNumber(exec, m_value.size())); 95 145 return true; 96 146 } … … 99 149 unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); 100 150 if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { 101 slot.setValue(jsS tring(exec, value().substr(i, 1)));151 slot.setValue(jsSingleCharacterSubstring(exec, m_value, i)); 102 152 return true; 103 153 } … … 109 159 { 110 160 if (propertyName < static_cast<unsigned>(m_value.size())) { 111 slot.setValue(jsS tring(exec, value().substr(propertyName, 1)));161 slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName)); 112 162 return true; 113 163 } -
trunk/JavaScriptCore/kjs/NumberPrototype.cpp
r35807 r36006 234 234 double x = v->uncheckedGetNumber(); 235 235 if (isnan(x)) 236 return js String(exec, "NaN");236 return jsNontrivialString(exec, "NaN"); 237 237 238 238 UString s; … … 340 340 341 341 if (isnan(x)) 342 return js String(exec, "NaN");342 return jsNontrivialString(exec, "NaN"); 343 343 344 344 if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0 … … 423 423 m = m.substr(0, 1) + "." + m.substr(1); 424 424 if (e >= 0) 425 return js String(exec, s + m + "e+" + UString::from(e));426 return js String(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)); 427 427 } 428 428 } else { … … 438 438 return jsString(exec, s + m); 439 439 } 440 return js String(exec, s + "0." + charSequence('0', -(e + 1)) + m);440 return jsNontrivialString(exec, s + "0." + charSequence('0', -(e + 1)) + m); 441 441 } 442 442 -
trunk/JavaScriptCore/kjs/ObjectPrototype.cpp
r35807 r36006 127 127 JSValue* objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) 128 128 { 129 return jsString(exec, thisValue->toThisObject(exec)->toString(exec));129 return thisValue->toThisJSString(exec); 130 130 } 131 131 132 132 JSValue* objectProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) 133 133 { 134 return js String(exec, "[object " + thisValue->toThisObject(exec)->className() + "]");134 return jsNontrivialString(exec, "[object " + thisValue->toThisObject(exec)->className() + "]"); 135 135 } 136 136 -
trunk/JavaScriptCore/kjs/RegExpConstructor.cpp
r35807 r36006 72 72 } 73 73 74 UString input; 74 75 UString lastInput; 75 76 OwnArrayPtr<int> lastOvector; … … 107 108 length = tmpOvector[1] - tmpOvector[0]; 108 109 110 d->input = s; 109 111 d->lastInput = s; 110 112 d->lastOvector.set(tmpOvector.release()); … … 134 136 { 135 137 RegExpConstructorPrivate* d = new RegExpConstructorPrivate; 138 d->input = data->lastInput; 136 139 d->lastInput = data->lastInput; 137 140 d->lastNumSubPatterns = data->lastNumSubPatterns; … … 159 162 int start = d->lastOvector[2 * i]; 160 163 if (start >= 0) 161 JSArray::put(exec, i, jsS tring(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)); 162 165 } 163 166 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)); 165 168 166 169 delete d; … … 175 178 JSValue* RegExpConstructor::getBackref(ExecState* exec, unsigned i) const 176 179 { 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); 180 186 } 181 187 … … 185 191 if (i > 0) { 186 192 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); 190 198 } 191 199 … … 193 201 { 194 202 if (d->lastOvector) 195 return jsS tring(exec, d->lastInput.substr(0, d->lastOvector[0]));196 return js String(exec, "");203 return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]); 204 return jsEmptyString(exec); 197 205 } 198 206 199 207 JSValue* RegExpConstructor::getRightContext(ExecState* exec) const 200 208 { 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); 206 212 } 207 213 … … 233 239 return getBackref(exec, 9); 234 240 case Input: 235 return jsString(exec, d-> lastInput);241 return jsString(exec, d->input); 236 242 case Multiline: 237 243 return jsBoolean(d->multiline); … … 248 254 } 249 255 250 return js String(exec, "");256 return jsEmptyString(exec); 251 257 } 252 258 … … 260 266 switch (token) { 261 267 case Input: 262 d-> lastInput = value->toString(exec);268 d->input = value->toString(exec); 263 269 break; 264 270 case Multiline: … … 318 324 // Can detect a distinct initial state that is invisible to JavaScript, by checking for null 319 325 // state (since jsString turns null strings to empty strings). 320 return d-> lastInput;326 return d->input; 321 327 } 322 328 -
trunk/JavaScriptCore/kjs/RegExpPrototype.cpp
r35807 r36006 102 102 if (!thisValue->isObject(&RegExpObject::info)) { 103 103 if (thisValue->isObject(&RegExpPrototype::info)) 104 return js String(exec, "//");104 return jsNontrivialString(exec, "//"); 105 105 return throwError(exec, TypeError); 106 106 } 107 107 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('/'); 109 110 if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().global)->toBoolean(exec)) 110 result += "g";111 result.append('g'); 111 112 if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec)) 112 result += "i";113 result.append('i'); 113 114 if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean(exec)) 114 result += "m";115 return js String(exec, result);115 result.append('m'); 116 return jsNontrivialString(exec, result); 116 117 } 117 118 -
trunk/JavaScriptCore/kjs/StringConstructor.cpp
r35807 r36006 29 29 namespace KJS { 30 30 31 static 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 31 41 static JSValue* stringFromCharCode(ExecState* exec, JSObject*, JSValue*, const ArgList& args) 32 42 { 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); 45 46 } 46 47 … … 79 80 { 80 81 if (args.isEmpty()) 81 return js String(exec, "");82 return jsEmptyString(exec); 82 83 return jsString(exec, args.at(exec, 0)->toString(exec)); 83 84 } -
trunk/JavaScriptCore/kjs/StringObject.cpp
r35807 r36006 33 33 : JSWrapperObject(prototype) 34 34 { 35 setInternalValue(js String(exec, ""));35 setInternalValue(jsEmptyString(exec)); 36 36 } 37 37 -
trunk/JavaScriptCore/kjs/StringPrototype.cpp
r35807 r36006 251 251 args.append(jsUndefined()); 252 252 else 253 args.append(jsS tring(exec, source.substr(matchStart, matchLen)));253 args.append(jsSubstring(exec, source, matchStart, matchLen)); 254 254 } 255 255 … … 293 293 if (callType != CallTypeNone) { 294 294 ArgList args; 295 args.append(jsS tring(exec, source.substr(matchPos, matchLen)));295 args.append(jsSubstring(exec, source, matchPos, matchLen)); 296 296 args.append(jsNumber(exec, matchPos)); 297 297 args.append(sourceVal); … … 319 319 { 320 320 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 } 325 329 double dpos = a0->toInteger(exec); 326 330 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); 331 333 } 332 334 … … 334 336 { 335 337 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 } 341 346 double dpos = a0->toInteger(exec); 342 347 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); 347 350 } 348 351 … … 424 427 int lastIndex = 0; 425 428 while (pos >= 0) { 426 list.append(jsS tring(exec, u.substr(pos, matchLength)));429 list.append(jsSubstring(exec, u, pos, matchLength)); 427 430 lastIndex = pos; 428 431 pos += matchLength == 0 ? 1 : matchLength; … … 484 487 if (to > len) 485 488 to = len; 486 return jsS tring(exec, s.substr(static_cast<int>(from), static_cast<int>(to - from)));487 } 488 489 return js String(exec, "");489 return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)); 490 } 491 492 return jsEmptyString(exec); 490 493 } 491 494 … … 497 500 JSValue* a1 = args.at(exec, 1); 498 501 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; 504 504 int p0 = 0; 505 u int32_tlimit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);505 unsigned limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec); 506 506 if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpObject::info)) { 507 507 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) { 509 509 // empty string matched by regexp -> empty array 510 res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));511 510 return result; 512 511 } 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()) { 515 514 OwnArrayPtr<int> ovector; 516 int mpos = reg->match( u, pos, &ovector);515 int mpos = reg->match(s, pos, &ovector); 517 516 if (mpos < 0) 518 517 break; … … 520 519 pos = mpos + (mlen == 0 ? 1 : mlen); 521 520 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)); 523 522 p0 = mpos + mlen; 524 i++;525 523 } 526 524 for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) { 527 525 int spos = ovector[si * 2]; 528 526 if (spos < 0) 529 res ->put(exec, i++, jsUndefined());527 result->put(exec, i++, jsUndefined()); 530 528 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)); 532 530 } 533 531 } … … 535 533 UString u2 = a0->toString(exec); 536 534 if (u2.isEmpty()) { 537 if ( u.isEmpty()) {535 if (s.isEmpty()) { 538 536 // empty separator matches empty string -> empty array 539 res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));540 537 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)));544 538 } 539 while (i != limit && p0 < s.size() - 1) 540 result->put(exec, i++, jsSingleCharacterSubstring(exec, s, p0++)); 545 541 } 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)); 548 545 p0 = pos + u2.size(); 549 i++;550 546 } 551 547 } 552 548 } 553 549 554 // add remaining string , if any555 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 558 554 return result; 559 555 } … … 570 566 double length = a1->isUndefined() ? len : a1->toInteger(exec); 571 567 if (start >= len) 572 return js String(exec, "");568 return jsEmptyString(exec); 573 569 if (length < 0) 574 return js String(exec, "");570 return jsEmptyString(exec); 575 571 if (start < 0) { 576 572 start += len; … … 580 576 if (length > len) 581 577 length = len; 582 return jsS tring(exec, s.substr(static_cast<int>(start), static_cast<int>(length)));578 return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length)); 583 579 } 584 580 … … 612 608 start = temp; 613 609 } 614 return jsS tring(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)); 615 611 } 616 612 -
trunk/JavaScriptCore/kjs/collector.cpp
r35853 r36006 970 970 ArgList::markLists(*m_markListSet); 971 971 m_globalData->machine->registerFile().markCallFrames(this); 972 m_globalData->smallStrings.mark(); 972 973 973 974 JAVASCRIPTCORE_GC_MARKED(); -
trunk/JavaScriptCore/kjs/ustring.cpp
r35691 r36006 395 395 396 396 // put these early so they can be inlined 397 inline size_t UString::expandedSize(size_t size, size_t otherSize) const397 inline size_t UString::expandedSize(size_t size, size_t otherSize) 398 398 { 399 399 // Do the size calculation in two parts, returning overflowIndicator if … … 432 432 if (!r->buf) { 433 433 r->buf = oldBuf; 434 m _rep = &Rep::null;434 makeNull(); 435 435 return; 436 436 } … … 455 455 UChar* newBuf = allocChars(newCapacity); 456 456 if (!newBuf) { 457 m _rep = &Rep::null;457 makeNull(); 458 458 return; 459 459 } … … 485 485 UChar* d = allocChars(length); 486 486 if (!d) 487 m _rep = &Rep::null;487 makeNull(); 488 488 else { 489 489 for (size_t i = 0; i < length; i++) … … 519 519 } 520 520 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; 521 PassRefPtr<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; 531 530 int length = aSize + bSize; 532 531 533 532 // possible cases: 534 533 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)) { 543 550 // - a reaches the end of its buffer so it qualifies for shared append 544 551 // - also, it's at least a quarter the length of b - appending to a much shorter … … 547 554 UString x(a); 548 555 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) { 555 569 // - b reaches the beginning of its buffer so it qualifies for shared prepend 556 570 // - also, it's at least a quarter the length of a - prepending to a much shorter … … 558 572 UString y(b); 559 573 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; 581 601 } 582 602 … … 807 827 UChar* d = allocChars(newCapacity); 808 828 if (!d) 809 m _rep = &Rep::null;829 makeNull(); 810 830 else { 811 831 memcpy(d, data(), thisSize * sizeof(UChar)); … … 856 876 UChar* d = allocChars(newCapacity); 857 877 if (!d) 858 m _rep = &Rep::null;878 makeNull(); 859 879 else { 860 880 memcpy(d, data(), thisSize * sizeof(UChar)); … … 909 929 UChar* d = allocChars(newCapacity); 910 930 if (!d) 911 m _rep = &Rep::null;931 makeNull(); 912 932 else { 913 933 memcpy(d, data(), thisSize * sizeof(UChar)); … … 937 957 UChar* d = allocChars(newCapacity); 938 958 if (!d) 939 m _rep = &Rep::null;959 makeNull(); 940 960 else { 941 961 d[0] = c; … … 965 985 UChar* d = allocChars(newCapacity); 966 986 if (!d) 967 m _rep = &Rep::null;987 makeNull(); 968 988 else { 969 989 memcpy(d, data(), length * sizeof(UChar)); … … 1043 1063 d = allocChars(l); 1044 1064 if (!d) { 1045 m _rep = &Rep::null;1065 makeNull(); 1046 1066 return *this; 1047 1067 } … … 1076 1096 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const 1077 1097 { 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 } 1079 1106 1080 1107 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk … … 1092 1119 if (*c == '\0') 1093 1120 return tolerateEmptyString ? 0.0 : NaN; 1121 1122 double d; 1094 1123 1095 1124 // hex number ? … … 1335 1364 bool operator==(const UString& s1, const UString& s2) 1336 1365 { 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 } 1341 1375 } 1342 1376 … … 1449 1483 } 1450 1484 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. 1486 NEVER_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. 1492 NEVER_INLINE UString::Rep* UString::nullRep() 1493 { 1494 return &Rep::null; 1495 } 1496 1451 1497 } // namespace KJS -
trunk/JavaScriptCore/kjs/ustring.h
r35458 r36006 72 72 73 73 class UString { 74 friend bool operator==(const UString&, const UString&);75 76 74 public: 77 75 struct Rep { … … 140 138 141 139 UString(const Vector<UChar>& buffer); 142 143 // Concatenation constructor. Makes operator+ more efficient.144 UString(const UString&, const UString&);145 140 146 141 ~UString() … … 235 230 236 231 Rep* rep() const { return m_rep.get(); } 232 static Rep* nullRep(); 237 233 238 234 UString(PassRefPtr<Rep> r) … … 245 241 246 242 private: 247 s ize_t expandedSize(size_t size, size_t otherSize) const;243 static size_t expandedSize(size_t size, size_t otherSize); 248 244 int usedCapacity() const; 249 245 int usedPreCapacity() const; 250 246 void expandCapacity(int requiredLength); 251 247 void expandPreCapacity(int requiredPreCap); 248 void makeNull(); 252 249 253 250 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 }; 257 255 258 256 inline bool operator!=(const UString& s1, const UString& s2) … … 281 279 } 282 280 283 bool operator==(const CString& s1, const CString& s2);281 bool operator==(const CString&, const CString&); 284 282 285 283 inline UString operator+(const UString& s1, const UString& s2) 286 284 { 287 return UString(s1, s2); 285 RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep()); 286 return UString(result ? result.release() : UString::nullRep()); 288 287 } 289 288 -
trunk/LayoutTests/ChangeLog
r35994 r36006 1 2008-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 1 14 2008-08-29 Eric Carlson <eric.carlson@apple.com> 2 15 -
trunk/LayoutTests/fast/js/regexp-caching-expected.txt
r20023 r36006 42 42 43 43 Properties 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} 53 53 input: {0} 54 lastMatch: { }55 lastParen: { }56 leftContext: { 0}54 lastMatch: {1234567890} 55 lastParen: {0} 56 leftContext: {<} 57 57 multiline: {true} 58 rightContext: { }58 rightContext: {>} 59 59 60 60 ---------- [Cleared RegExp values] ---------- -
trunk/WebCore/ChangeLog
r36002 r36006 1 2008-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 1 16 2008-08-29 Brady Eidson <beidson@apple.com> 2 17 -
trunk/WebCore/bindings/js/JSDOMWindowBase.cpp
r35964 r36006 939 939 JSValue* v = args.at(exec, 0); 940 940 if (v->isNull()) 941 return js String(exec);941 return jsEmptyString(exec); 942 942 943 943 UString s = v->toString(exec); … … 971 971 JSValue* v = args.at(exec, 0); 972 972 if (v->isNull()) 973 return js String(exec);973 return jsEmptyString(exec); 974 974 975 975 UString s = v->toString(exec); -
trunk/WebCore/bindings/js/JSEventListener.cpp
r35853 r36006 245 245 JSValue* JSLazyEventListener::eventParameterName() const 246 246 { 247 static ProtectedPtr<JSValue> eventString = js String(window()->globalExec(), "event");247 static ProtectedPtr<JSValue> eventString = jsNontrivialString(window()->globalExec(), "event"); 248 248 return eventString.get(); 249 249 } -
trunk/WebCore/bindings/js/JSSVGLazyEventListener.cpp
r34659 r36006 38 38 JSValue* JSSVGLazyEventListener::eventParameterName() const 39 39 { 40 static ProtectedPtr<JSValue> eventString = js String(window()->globalExec(), "evt");40 static ProtectedPtr<JSValue> eventString = jsNontrivialString(window()->globalExec(), "evt"); 41 41 return eventString.get(); 42 42 }
Note:
See TracChangeset
for help on using the changeset viewer.