Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / JavaScriptCore / runtime / StringPrototype.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
4  *  Copyright (C) 2009 Torch Mobile, Inc.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "config.h"
23 #include "StringPrototype.h"
24
25 #include "ButterflyInlines.h"
26 #include "CachedCall.h"
27 #include "CopiedSpaceInlines.h"
28 #include "Error.h"
29 #include "Executable.h"
30 #include "JSGlobalObjectFunctions.h"
31 #include "JSArray.h"
32 #include "JSFunction.h"
33 #include "JSStringBuilder.h"
34 #include "Lookup.h"
35 #include "ObjectPrototype.h"
36 #include "Operations.h"
37 #include "PropertyNameArray.h"
38 #include "RegExpCache.h"
39 #include "RegExpConstructor.h"
40 #include "RegExpMatchesArray.h"
41 #include "RegExpObject.h"
42 #include <wtf/ASCIICType.h>
43 #include <wtf/MathExtras.h>
44 #include <wtf/unicode/Collator.h>
45
46 using namespace WTF;
47
48 namespace JSC {
49
50 ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringPrototype);
51
52 static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
56 static EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
57 static EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
58 static EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
59 static EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
60 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
61 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
62 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
63 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
64 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
65 static EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
66 static EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
67 static EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
68 static EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
69 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
70 static EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
71 static EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
72 static EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
73 static EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
74 static EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
75 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
76 static EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
77 static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
78 static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
79 static EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
80 static EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
81 static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
82 static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
83 static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
84
85 const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) };
86
87 // ECMA 15.5.4
88 StringPrototype::StringPrototype(ExecState* exec, Structure* structure)
89     : StringObject(exec->vm(), structure)
90 {
91 }
92
93 void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, JSString* nameAndMessage)
94 {
95     VM& vm = exec->vm();
96     
97     Base::finishCreation(vm, nameAndMessage);
98     ASSERT(inherits(info()));
99
100     JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
101     JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
102     JSC_NATIVE_INTRINSIC_FUNCTION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
103     JSC_NATIVE_INTRINSIC_FUNCTION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
104     JSC_NATIVE_FUNCTION("concat", stringProtoFuncConcat, DontEnum, 1);
105     JSC_NATIVE_FUNCTION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
106     JSC_NATIVE_FUNCTION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
107     JSC_NATIVE_FUNCTION("match", stringProtoFuncMatch, DontEnum, 1);
108     JSC_NATIVE_FUNCTION("replace", stringProtoFuncReplace, DontEnum, 2);
109     JSC_NATIVE_FUNCTION("search", stringProtoFuncSearch, DontEnum, 1);
110     JSC_NATIVE_FUNCTION("slice", stringProtoFuncSlice, DontEnum, 2);
111     JSC_NATIVE_FUNCTION("split", stringProtoFuncSplit, DontEnum, 2);
112     JSC_NATIVE_FUNCTION("substr", stringProtoFuncSubstr, DontEnum, 2);
113     JSC_NATIVE_FUNCTION("substring", stringProtoFuncSubstring, DontEnum, 2);
114     JSC_NATIVE_FUNCTION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
115     JSC_NATIVE_FUNCTION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
116     JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
117     JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
118     JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
119     JSC_NATIVE_FUNCTION("big", stringProtoFuncBig, DontEnum, 0);
120     JSC_NATIVE_FUNCTION("small", stringProtoFuncSmall, DontEnum, 0);
121     JSC_NATIVE_FUNCTION("blink", stringProtoFuncBlink, DontEnum, 0);
122     JSC_NATIVE_FUNCTION("bold", stringProtoFuncBold, DontEnum, 0);
123     JSC_NATIVE_FUNCTION("fixed", stringProtoFuncFixed, DontEnum, 0);
124     JSC_NATIVE_FUNCTION("italics", stringProtoFuncItalics, DontEnum, 0);
125     JSC_NATIVE_FUNCTION("strike", stringProtoFuncStrike, DontEnum, 0);
126     JSC_NATIVE_FUNCTION("sub", stringProtoFuncSub, DontEnum, 0);
127     JSC_NATIVE_FUNCTION("sup", stringProtoFuncSup, DontEnum, 0);
128     JSC_NATIVE_FUNCTION("fontcolor", stringProtoFuncFontcolor, DontEnum, 1);
129     JSC_NATIVE_FUNCTION("fontsize", stringProtoFuncFontsize, DontEnum, 1);
130     JSC_NATIVE_FUNCTION("anchor", stringProtoFuncAnchor, DontEnum, 1);
131     JSC_NATIVE_FUNCTION("link", stringProtoFuncLink, DontEnum, 1);
132     JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0);
133     JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
134     JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
135
136     // The constructor will be added later, after StringConstructor has been built
137     putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
138 }
139
140 StringPrototype* StringPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
141 {
142     JSString* empty = jsEmptyString(exec);
143     StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
144     prototype->finishCreation(exec, globalObject, empty);
145     return prototype;
146 }
147
148 // ------------------------------ Functions --------------------------
149
150 // Helper for producing a JSString for 'string', where 'string' was been produced by
151 // calling ToString on 'originalValue'. In cases where 'originalValue' already was a
152 // string primitive we can just use this, otherwise we need to allocate a new JSString.
153 static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue, const String& string)
154 {
155     if (originalValue.isString()) {
156         ASSERT(asString(originalValue)->value(exec) == string);
157         return asString(originalValue);
158     }
159     return jsString(exec, string);
160 }
161
162 template <typename CharType>
163 static NEVER_INLINE String substituteBackreferencesSlow(const String& replacement, const String& source, const int* ovector, RegExp* reg, size_t i)
164 {
165     Vector<CharType> substitutedReplacement;
166     int offset = 0;
167     do {
168         if (i + 1 == replacement.length())
169             break;
170
171         UChar ref = replacement[i + 1];
172         if (ref == '$') {
173             // "$$" -> "$"
174             ++i;
175             substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset);
176             offset = i + 1;
177             continue;
178         }
179
180         int backrefStart;
181         int backrefLength;
182         int advance = 0;
183         if (ref == '&') {
184             backrefStart = ovector[0];
185             backrefLength = ovector[1] - backrefStart;
186         } else if (ref == '`') {
187             backrefStart = 0;
188             backrefLength = ovector[0];
189         } else if (ref == '\'') {
190             backrefStart = ovector[1];
191             backrefLength = source.length() - backrefStart;
192         } else if (reg && ref >= '0' && ref <= '9') {
193             // 1- and 2-digit back references are allowed
194             unsigned backrefIndex = ref - '0';
195             if (backrefIndex > reg->numSubpatterns())
196                 continue;
197             if (replacement.length() > i + 2) {
198                 ref = replacement[i + 2];
199                 if (ref >= '0' && ref <= '9') {
200                     backrefIndex = 10 * backrefIndex + ref - '0';
201                     if (backrefIndex > reg->numSubpatterns())
202                         backrefIndex = backrefIndex / 10;   // Fall back to the 1-digit reference
203                     else
204                         advance = 1;
205                 }
206             }
207             if (!backrefIndex)
208                 continue;
209             backrefStart = ovector[2 * backrefIndex];
210             backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
211         } else
212             continue;
213
214         if (i - offset)
215             substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset);
216         i += 1 + advance;
217         offset = i + 1;
218         if (backrefStart >= 0)
219             substitutedReplacement.append(source.getCharactersWithUpconvert<CharType>() + backrefStart, backrefLength);
220     } while ((i = replacement.find('$', i + 1)) != notFound);
221
222     if (replacement.length() - offset)
223         substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, replacement.length() - offset);
224
225     substitutedReplacement.shrinkToFit();
226     return String::adopt(substitutedReplacement);
227 }
228
229 static inline String substituteBackreferences(const String& replacement, const String& source, const int* ovector, RegExp* reg)
230 {
231     size_t i = replacement.find('$');
232     if (UNLIKELY(i != notFound)) {
233         if (replacement.is8Bit() && source.is8Bit())
234             return substituteBackreferencesSlow<LChar>(replacement, source, ovector, reg, i);
235         return substituteBackreferencesSlow<UChar>(replacement, source, ovector, reg, i);
236     }
237     return replacement;
238 }
239
240 static inline int localeCompare(const String& a, const String& b)
241 {
242     return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.characters()), a.length(), reinterpret_cast<const ::UChar*>(b.characters()), b.length());
243 }
244
245 struct StringRange {
246 public:
247     StringRange(int pos, int len)
248         : position(pos)
249         , length(len)
250     {
251     }
252
253     StringRange()
254     {
255     }
256
257     int position;
258     int length;
259 };
260
261 static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourceVal, const String& source, const StringRange* substringRanges, int rangeCount)
262 {
263     if (rangeCount == 1) {
264         int sourceSize = source.length();
265         int position = substringRanges[0].position;
266         int length = substringRanges[0].length;
267         if (position <= 0 && length >= sourceSize)
268             return sourceVal;
269         // We could call String::substringSharingImpl(), but this would result in redundant checks.
270         return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length)));
271     }
272
273     int totalLength = 0;
274     for (int i = 0; i < rangeCount; i++)
275         totalLength += substringRanges[i].length;
276
277     if (!totalLength)
278         return jsEmptyString(exec);
279
280     if (source.is8Bit()) {
281         LChar* buffer;
282         const LChar* sourceData = source.characters8();
283         RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
284         if (!impl)
285             return throwOutOfMemoryError(exec);
286
287         int bufferPos = 0;
288         for (int i = 0; i < rangeCount; i++) {
289             if (int srcLen = substringRanges[i].length) {
290                 StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
291                 bufferPos += srcLen;
292             }
293         }
294
295         return jsString(exec, impl.release());
296     }
297
298     UChar* buffer;
299     const UChar* sourceData = source.characters16();
300
301     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
302     if (!impl)
303         return throwOutOfMemoryError(exec);
304
305     int bufferPos = 0;
306     for (int i = 0; i < rangeCount; i++) {
307         if (int srcLen = substringRanges[i].length) {
308             StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
309             bufferPos += srcLen;
310         }
311     }
312
313     return jsString(exec, impl.release());
314 }
315
316 static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const String& source, const StringRange* substringRanges, int rangeCount, const String* separators, int separatorCount)
317 {
318     if (rangeCount == 1 && separatorCount == 0) {
319         int sourceSize = source.length();
320         int position = substringRanges[0].position;
321         int length = substringRanges[0].length;
322         if (position <= 0 && length >= sourceSize)
323             return sourceVal;
324         // We could call String::substringSharingImpl(), but this would result in redundant checks.
325         return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length)));
326     }
327
328     Checked<int, RecordOverflow> totalLength = 0;
329     bool allSeparators8Bit = true;
330     for (int i = 0; i < rangeCount; i++)
331         totalLength += substringRanges[i].length;
332     for (int i = 0; i < separatorCount; i++) {
333         totalLength += separators[i].length();
334         if (separators[i].length() && !separators[i].is8Bit())
335             allSeparators8Bit = false;
336     }
337     if (totalLength.hasOverflowed())
338         return throwOutOfMemoryError(exec);
339
340     if (!totalLength)
341         return jsEmptyString(exec);
342
343     if (source.is8Bit() && allSeparators8Bit) {
344         LChar* buffer;
345         const LChar* sourceData = source.characters8();
346
347         RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer);
348         if (!impl)
349             return throwOutOfMemoryError(exec);
350
351         int maxCount = std::max(rangeCount, separatorCount);
352         int bufferPos = 0;
353         for (int i = 0; i < maxCount; i++) {
354             if (i < rangeCount) {
355                 if (int srcLen = substringRanges[i].length) {
356                     StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
357                     bufferPos += srcLen;
358                 }
359             }
360             if (i < separatorCount) {
361                 if (int sepLen = separators[i].length()) {
362                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
363                     bufferPos += sepLen;
364                 }
365             }
366         }        
367
368         return jsString(exec, impl.release());
369     }
370
371     UChar* buffer;
372     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer);
373     if (!impl)
374         return throwOutOfMemoryError(exec);
375
376     int maxCount = std::max(rangeCount, separatorCount);
377     int bufferPos = 0;
378     for (int i = 0; i < maxCount; i++) {
379         if (i < rangeCount) {
380             if (int srcLen = substringRanges[i].length) {
381                 if (source.is8Bit())
382                     StringImpl::copyChars(buffer + bufferPos, source.characters8() + substringRanges[i].position, srcLen);
383                 else
384                     StringImpl::copyChars(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
385                 bufferPos += srcLen;
386             }
387         }
388         if (i < separatorCount) {
389             if (int sepLen = separators[i].length()) {
390                 if (separators[i].is8Bit())
391                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
392                 else
393                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters16(), sepLen);
394                 bufferPos += sepLen;
395             }
396         }
397     }
398
399     return jsString(exec, impl.release());
400 }
401
402 static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
403 {
404     size_t lastIndex = 0;
405     unsigned startPosition = 0;
406
407     Vector<StringRange, 16> sourceRanges;
408     VM* vm = &exec->vm();
409     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
410     unsigned sourceLen = source.length();
411
412     while (true) {
413         MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition);
414         if (!result)
415             break;
416
417         if (lastIndex < result.start)
418             sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
419
420         lastIndex = result.end;
421         startPosition = lastIndex;
422
423         // special case of empty match
424         if (result.empty()) {
425             startPosition++;
426             if (startPosition > sourceLen)
427                 break;
428         }
429     }
430
431     if (!lastIndex)
432         return JSValue::encode(string);
433
434     if (static_cast<unsigned>(lastIndex) < sourceLen)
435         sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
436
437     return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
438 }
439
440 static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
441 {
442     JSValue replaceValue = exec->argument(1);
443     String replacementString;
444     CallData callData;
445     CallType callType = getCallData(replaceValue, callData);
446     if (callType == CallTypeNone)
447         replacementString = replaceValue.toString(exec)->value(exec);
448
449     const String& source = string->value(exec);
450     unsigned sourceLen = source.length();
451     if (exec->hadException())
452         return JSValue::encode(JSValue());
453     RegExpObject* regExpObject = asRegExpObject(searchValue);
454     RegExp* regExp = regExpObject->regExp();
455     bool global = regExp->global();
456
457     if (global) {
458         // ES5.1 15.5.4.10 step 8.a.
459         regExpObject->setLastIndex(exec, 0);
460         if (exec->hadException())
461             return JSValue::encode(JSValue());
462
463         if (callType == CallTypeNone && !replacementString.length())
464             return removeUsingRegExpSearch(exec, string, source, regExp);
465     }
466
467     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
468
469     size_t lastIndex = 0;
470     unsigned startPosition = 0;
471
472     Vector<StringRange, 16> sourceRanges;
473     Vector<String, 16> replacements;
474
475     // This is either a loop (if global is set) or a one-way (if not).
476     if (global && callType == CallTypeJS) {
477         // regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
478         int argCount = regExp->numSubpatterns() + 1 + 2;
479         JSFunction* func = jsCast<JSFunction*>(replaceValue);
480         CachedCall cachedCall(exec, func, argCount);
481         if (exec->hadException())
482             return JSValue::encode(jsNull());
483         VM* vm = &exec->vm();
484         if (source.is8Bit()) {
485             while (true) {
486                 int* ovector;
487                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
488                 if (!result)
489                     break;
490
491                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
492
493                 unsigned i = 0;
494                 for (; i < regExp->numSubpatterns() + 1; ++i) {
495                     int matchStart = ovector[i * 2];
496                     int matchLen = ovector[i * 2 + 1] - matchStart;
497
498                     if (matchStart < 0)
499                         cachedCall.setArgument(i, jsUndefined());
500                     else
501                         cachedCall.setArgument(i, jsSubstring8(vm, source, matchStart, matchLen));
502                 }
503
504                 cachedCall.setArgument(i++, jsNumber(result.start));
505                 cachedCall.setArgument(i++, string);
506
507                 cachedCall.setThis(jsUndefined());
508                 JSValue jsResult = cachedCall.call();
509                 replacements.append(jsResult.toString(cachedCall.newCallFrame(exec))->value(exec));
510                 if (exec->hadException())
511                     break;
512
513                 lastIndex = result.end;
514                 startPosition = lastIndex;
515
516                 // special case of empty match
517                 if (result.empty()) {
518                     startPosition++;
519                     if (startPosition > sourceLen)
520                         break;
521                 }
522             }
523         } else {
524             while (true) {
525                 int* ovector;
526                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
527                 if (!result)
528                     break;
529
530                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
531
532                 unsigned i = 0;
533                 for (; i < regExp->numSubpatterns() + 1; ++i) {
534                     int matchStart = ovector[i * 2];
535                     int matchLen = ovector[i * 2 + 1] - matchStart;
536
537                     if (matchStart < 0)
538                         cachedCall.setArgument(i, jsUndefined());
539                     else
540                         cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen));
541                 }
542
543                 cachedCall.setArgument(i++, jsNumber(result.start));
544                 cachedCall.setArgument(i++, string);
545
546                 cachedCall.setThis(jsUndefined());
547                 JSValue jsResult = cachedCall.call();
548                 replacements.append(jsResult.toString(cachedCall.newCallFrame(exec))->value(exec));
549                 if (exec->hadException())
550                     break;
551
552                 lastIndex = result.end;
553                 startPosition = lastIndex;
554
555                 // special case of empty match
556                 if (result.empty()) {
557                     startPosition++;
558                     if (startPosition > sourceLen)
559                         break;
560                 }
561             }
562         }
563     } else {
564         VM* vm = &exec->vm();
565         do {
566             int* ovector;
567             MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
568             if (!result)
569                 break;
570
571             if (callType != CallTypeNone) {
572                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
573
574                 MarkedArgumentBuffer args;
575
576                 for (unsigned i = 0; i < regExp->numSubpatterns() + 1; ++i) {
577                     int matchStart = ovector[i * 2];
578                     int matchLen = ovector[i * 2 + 1] - matchStart;
579
580                     if (matchStart < 0)
581                         args.append(jsUndefined());
582                     else
583                         args.append(jsSubstring(exec, source, matchStart, matchLen));
584                 }
585
586                 args.append(jsNumber(result.start));
587                 args.append(string);
588
589                 replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec));
590                 if (exec->hadException())
591                     break;
592             } else {
593                 int replLen = replacementString.length();
594                 if (lastIndex < result.start || replLen) {
595                     sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
596
597                     if (replLen)
598                         replacements.append(substituteBackreferences(replacementString, source, ovector, regExp));
599                     else
600                         replacements.append(String());
601                 }
602             }
603
604             lastIndex = result.end;
605             startPosition = lastIndex;
606
607             // special case of empty match
608             if (result.empty()) {
609                 startPosition++;
610                 if (startPosition > sourceLen)
611                     break;
612             }
613         } while (global);
614     }
615
616     if (!lastIndex && replacements.isEmpty())
617         return JSValue::encode(string);
618
619     if (static_cast<unsigned>(lastIndex) < sourceLen)
620         sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
621
622     return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
623 }
624
625 static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
626 {
627     const String& string = jsString->value(exec);
628     String searchString = searchValue.toString(exec)->value(exec);
629     if (exec->hadException())
630         return JSValue::encode(jsUndefined());
631
632     size_t matchStart = string.find(searchString);
633
634     if (matchStart == notFound)
635         return JSValue::encode(jsString);
636
637     JSValue replaceValue = exec->argument(1);
638     CallData callData;
639     CallType callType = getCallData(replaceValue, callData);
640     if (callType != CallTypeNone) {
641         MarkedArgumentBuffer args;
642         args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
643         args.append(jsNumber(matchStart));
644         args.append(jsString);
645         replaceValue = call(exec, replaceValue, callType, callData, jsUndefined(), args);
646         if (exec->hadException())
647             return JSValue::encode(jsUndefined());
648     }
649
650     String replaceString = replaceValue.toString(exec)->value(exec);
651     if (exec->hadException())
652         return JSValue::encode(jsUndefined());
653
654     StringImpl* stringImpl = string.impl();
655     String leftPart(StringImpl::create(stringImpl, 0, matchStart));
656
657     size_t matchEnd = matchStart + searchString.impl()->length();
658     int ovector[2] = { static_cast<int>(matchStart),  static_cast<int>(matchEnd)};
659     String middlePart = substituteBackreferences(replaceString, string, ovector, 0);
660
661     size_t leftLength = stringImpl->length() - matchEnd;
662     String rightPart(StringImpl::create(stringImpl, matchEnd, leftLength));
663     return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart));
664 }
665
666 static inline bool checkObjectCoercible(JSValue thisValue)
667 {
668     if (thisValue.isString())
669         return true;
670
671     if (thisValue.isUndefinedOrNull())
672         return false;
673
674     if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isEnvironmentRecord())
675         return false;
676
677     return true;
678 }
679
680 EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
681 {
682     JSValue thisValue = exec->hostThisValue();
683     if (!checkObjectCoercible(thisValue))
684         return throwVMTypeError(exec);
685     JSString* string = thisValue.toString(exec);
686     JSValue searchValue = exec->argument(0);
687
688     if (searchValue.inherits(RegExpObject::info()))
689         return replaceUsingRegExpSearch(exec, string, searchValue);
690     return replaceUsingStringSearch(exec, string, searchValue);
691 }
692
693 EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
694 {
695     JSValue thisValue = exec->hostThisValue();
696     // Also used for valueOf.
697
698     if (thisValue.isString())
699         return JSValue::encode(thisValue);
700
701     if (thisValue.inherits(StringObject::info()))
702         return JSValue::encode(asStringObject(thisValue)->internalValue());
703
704     return throwVMTypeError(exec);
705 }
706
707 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
708 {
709     JSValue thisValue = exec->hostThisValue();
710     if (!checkObjectCoercible(thisValue))
711         return throwVMTypeError(exec);
712     String s = thisValue.toString(exec)->value(exec);
713     unsigned len = s.length();
714     JSValue a0 = exec->argument(0);
715     if (a0.isUInt32()) {
716         uint32_t i = a0.asUInt32();
717         if (i < len)
718             return JSValue::encode(jsSingleCharacterSubstring(exec, s, i));
719         return JSValue::encode(jsEmptyString(exec));
720     }
721     double dpos = a0.toInteger(exec);
722     if (dpos >= 0 && dpos < len)
723         return JSValue::encode(jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos)));
724     return JSValue::encode(jsEmptyString(exec));
725 }
726
727 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
728 {
729     JSValue thisValue = exec->hostThisValue();
730     if (!checkObjectCoercible(thisValue))
731         return throwVMTypeError(exec);
732     String s = thisValue.toString(exec)->value(exec);
733     unsigned len = s.length();
734     JSValue a0 = exec->argument(0);
735     if (a0.isUInt32()) {
736         uint32_t i = a0.asUInt32();
737         if (i < len) {
738             if (s.is8Bit())
739                 return JSValue::encode(jsNumber(s.characters8()[i]));
740             return JSValue::encode(jsNumber(s.characters16()[i]));
741         }
742         return JSValue::encode(jsNaN());
743     }
744     double dpos = a0.toInteger(exec);
745     if (dpos >= 0 && dpos < len)
746         return JSValue::encode(jsNumber(s[static_cast<int>(dpos)]));
747     return JSValue::encode(jsNaN());
748 }
749
750 EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
751 {
752     JSValue thisValue = exec->hostThisValue();
753     if (thisValue.isString() && (exec->argumentCount() == 1))
754         return JSValue::encode(jsString(exec, asString(thisValue), exec->argument(0).toString(exec)));
755
756     if (!checkObjectCoercible(thisValue))
757         return throwVMTypeError(exec);
758     return JSValue::encode(jsStringFromArguments(exec, thisValue));
759 }
760
761 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
762 {
763     JSValue thisValue = exec->hostThisValue();
764     if (!checkObjectCoercible(thisValue))
765         return throwVMTypeError(exec);
766     String s = thisValue.toString(exec)->value(exec);
767
768     JSValue a0 = exec->argument(0);
769     JSValue a1 = exec->argument(1);
770     String u2 = a0.toString(exec)->value(exec);
771
772     size_t result;
773     if (a1.isUndefined())
774         result = s.find(u2);
775     else {
776         unsigned pos;
777         int len = s.length();
778         if (a1.isUInt32())
779             pos = std::min<uint32_t>(a1.asUInt32(), len);
780         else {
781             double dpos = a1.toInteger(exec);
782             if (dpos < 0)
783                 dpos = 0;
784             else if (dpos > len)
785                 dpos = len;
786             pos = static_cast<unsigned>(dpos);
787         }
788         result = s.find(u2, pos);
789     }
790
791     if (result == notFound)
792         return JSValue::encode(jsNumber(-1));
793     return JSValue::encode(jsNumber(result));
794 }
795
796 EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
797 {
798     JSValue thisValue = exec->hostThisValue();
799     if (!checkObjectCoercible(thisValue))
800         return throwVMTypeError(exec);
801     String s = thisValue.toString(exec)->value(exec);
802     int len = s.length();
803
804     JSValue a0 = exec->argument(0);
805     JSValue a1 = exec->argument(1);
806
807     String u2 = a0.toString(exec)->value(exec);
808     double dpos = a1.toIntegerPreserveNaN(exec);
809     if (dpos < 0)
810         dpos = 0;
811     else if (!(dpos <= len)) // true for NaN
812         dpos = len;
813
814     size_t result;
815     unsigned startPosition = static_cast<unsigned>(dpos);
816     if (!startPosition)
817         result = s.startsWith(u2) ? 0 : notFound;
818     else
819         result = s.reverseFind(u2, startPosition);
820     if (result == notFound)
821         return JSValue::encode(jsNumber(-1));
822     return JSValue::encode(jsNumber(result));
823 }
824
825 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
826 {
827     JSValue thisValue = exec->hostThisValue();
828     if (!checkObjectCoercible(thisValue))
829         return throwVMTypeError(exec);
830     JSString* string = thisValue.toString(exec);
831     String s = string->value(exec);
832     VM* vm = &exec->vm();
833
834     JSValue a0 = exec->argument(0);
835
836     RegExp* regExp;
837     bool global = false;
838     if (a0.inherits(RegExpObject::info())) {
839         RegExpObject* regExpObject = asRegExpObject(a0);
840         regExp = regExpObject->regExp();
841         if ((global = regExp->global())) {
842             // ES5.1 15.5.4.10 step 8.a.
843             regExpObject->setLastIndex(exec, 0);
844             if (exec->hadException())
845                 return JSValue::encode(JSValue());
846         }
847     } else {
848         /*
849          *  ECMA 15.5.4.12 String.prototype.search (regexp)
850          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
851          *  replaced with the result of the expression new RegExp(regexp).
852          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
853          */
854         regExp = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
855         if (!regExp->isValid())
856             return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
857     }
858     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
859     MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
860     // case without 'g' flag is handled like RegExp.prototype.exec
861     if (!global)
862         return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull());
863
864     // return array of matches
865     MarkedArgumentBuffer list;
866     while (result) {
867         size_t end = result.end;
868         size_t length = end - result.start;
869         list.append(jsSubstring(exec, s, result.start, length));
870         if (!length)
871             ++end;
872         result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
873     }
874     if (list.isEmpty()) {
875         // if there are no matches at all, it's important to return
876         // Null instead of an empty array, because this matches
877         // other browsers and because Null is a false value.
878         return JSValue::encode(jsNull());
879     }
880
881     return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
882 }
883
884 EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
885 {
886     JSValue thisValue = exec->hostThisValue();
887     if (!checkObjectCoercible(thisValue))
888         return throwVMTypeError(exec);
889     JSString* string = thisValue.toString(exec);
890     String s = string->value(exec);
891     VM* vm = &exec->vm();
892
893     JSValue a0 = exec->argument(0);
894
895     RegExp* reg;
896     if (a0.inherits(RegExpObject::info()))
897         reg = asRegExpObject(a0)->regExp();
898     else { 
899         /*
900          *  ECMA 15.5.4.12 String.prototype.search (regexp)
901          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
902          *  replaced with the result of the expression new RegExp(regexp).
903          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
904          */
905         reg = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
906         if (!reg->isValid())
907             return throwVMError(exec, createSyntaxError(exec, reg->errorMessage()));
908     }
909     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
910     MatchResult result = regExpConstructor->performMatch(*vm, reg, string, s, 0);
911     return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
912 }
913
914 EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
915 {
916     JSValue thisValue = exec->hostThisValue();
917     if (!checkObjectCoercible(thisValue))
918         return throwVMTypeError(exec);
919     String s = thisValue.toString(exec)->value(exec);
920     int len = s.length();
921
922     JSValue a0 = exec->argument(0);
923     JSValue a1 = exec->argument(1);
924
925     // The arg processing is very much like ArrayProtoFunc::Slice
926     double start = a0.toInteger(exec);
927     double end = a1.isUndefined() ? len : a1.toInteger(exec);
928     double from = start < 0 ? len + start : start;
929     double to = end < 0 ? len + end : end;
930     if (to > from && to > 0 && from < len) {
931         if (from < 0)
932             from = 0;
933         if (to > len)
934             to = len;
935         return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
936     }
937
938     return JSValue::encode(jsEmptyString(exec));
939 }
940
941 // Return true in case of early return (resultLength got to limitLength).
942 template<typename CharacterType>
943 static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
944 {
945     // 12. Let q = p.
946     size_t matchPosition;
947     const CharacterType* characters = string->getCharacters<CharacterType>();
948     // 13. Repeat, while q != s
949     //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
950     //   b. If z is failure, then let q = q+1.
951     //   c. Else, z is not failure
952     while ((matchPosition = WTF::find(characters, string->length(), separatorCharacter, position)) != notFound) {
953         // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
954         //    through q (exclusive).
955         // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
956         //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
957         result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
958         // 3. Increment lengthA by 1.
959         // 4. If lengthA == lim, return A.
960         if (++resultLength == limitLength)
961             return true;
962
963         // 5. Let p = e.
964         // 8. Let q = p.
965         position = matchPosition + 1;
966     }
967     return false;
968 }
969
970 // ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
971 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
972 {
973     // 1. Call CheckObjectCoercible passing the this value as its argument.
974     JSValue thisValue = exec->hostThisValue();
975     if (!checkObjectCoercible(thisValue))
976         return throwVMTypeError(exec);
977
978     // 2. Let S be the result of calling ToString, giving it the this value as its argument.
979     // 6. Let s be the number of characters in S.
980     String input = thisValue.toString(exec)->value(exec);
981
982     // 3. Let A be a new array created as if by the expression new Array()
983     //    where Array is the standard built-in constructor with that name.
984     JSArray* result = constructEmptyArray(exec, 0);
985
986     // 4. Let lengthA be 0.
987     unsigned resultLength = 0;
988
989     // 5. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
990     JSValue limitValue = exec->argument(1);
991     unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
992
993     // 7. Let p = 0.
994     size_t position = 0;
995
996     // 8. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
997     //    otherwise let R = ToString(separator).
998     JSValue separatorValue = exec->argument(0);
999     if (separatorValue.inherits(RegExpObject::info())) {
1000         VM* vm = &exec->vm();
1001         RegExp* reg = asRegExpObject(separatorValue)->regExp();
1002
1003         // 9. If lim == 0, return A.
1004         if (!limit)
1005             return JSValue::encode(result);
1006
1007         // 10. If separator is undefined, then
1008         if (separatorValue.isUndefined()) {
1009             // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1010             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1011             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1012             // b. Return A.
1013             return JSValue::encode(result);
1014         }
1015
1016         // 11. If s == 0, then
1017         if (input.isEmpty()) {
1018             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1019             // b. If z is not failure, return A.
1020             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1021             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1022             // d. Return A.
1023             if (!reg->match(*vm, input, 0))
1024                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1025             return JSValue::encode(result);
1026         }
1027
1028         // 12. Let q = p.
1029         size_t matchPosition = 0;
1030         // 13. Repeat, while q != s
1031         while (matchPosition < input.length()) {
1032             // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1033             Vector<int, 32> ovector;
1034             int mpos = reg->match(*vm, input, matchPosition, ovector);
1035             // b. If z is failure, then let q = q + 1.
1036             if (mpos < 0)
1037                 break;
1038             matchPosition = mpos;
1039
1040             // c. Else, z is not failure
1041             // i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
1042             size_t matchEnd = ovector[1];
1043
1044             // ii. If e == p, then let q = q + 1.
1045             if (matchEnd == position) {
1046                 ++matchPosition;
1047                 continue;
1048             }
1049             // iii. Else, e != p
1050
1051             // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1052             //    through q (exclusive).
1053             // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1054             //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1055             result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
1056             // 3. Increment lengthA by 1.
1057             // 4. If lengthA == lim, return A.
1058             if (++resultLength == limit)
1059                 return JSValue::encode(result);
1060
1061             // 5. Let p = e.
1062             // 8. Let q = p.
1063             position = matchEnd;
1064             matchPosition = matchEnd;
1065
1066             // 6. Let i = 0.
1067             // 7. Repeat, while i is not equal to the number of elements in cap.
1068             //  a Let i = i + 1.
1069             for (unsigned i = 1; i <= reg->numSubpatterns(); ++i) {
1070                 // b Call the [[DefineOwnProperty]] internal method of A with arguments
1071                 //   ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
1072                 //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1073                 int sub = ovector[i * 2];
1074                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub));
1075                 // c Increment lengthA by 1.
1076                 // d If lengthA == lim, return A.
1077                 if (++resultLength == limit)
1078                     return JSValue::encode(result);
1079             }
1080         }
1081     } else {
1082         String separator = separatorValue.toString(exec)->value(exec);
1083
1084         // 9. If lim == 0, return A.
1085         if (!limit)
1086             return JSValue::encode(result);
1087
1088         // 10. If separator is undefined, then
1089         JSValue separatorValue = exec->argument(0);
1090         if (separatorValue.isUndefined()) {
1091             // a.  Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1092             //     Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1093             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1094             // b.  Return A.
1095             return JSValue::encode(result);
1096         }
1097
1098         // 11. If s == 0, then
1099         if (input.isEmpty()) {
1100             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1101             // b. If z is not failure, return A.
1102             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1103             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1104             // d. Return A.
1105             if (!separator.isEmpty())
1106                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1107             return JSValue::encode(result);
1108         }
1109
1110         // Optimized case for splitting on the empty string.
1111         if (separator.isEmpty()) {
1112             limit = std::min(limit, input.length());
1113             // Zero limt/input length handled in steps 9/11 respectively, above.
1114             ASSERT(limit);
1115
1116             do {
1117                 result->putDirectIndex(exec, position, jsSingleCharacterSubstring(exec, input, position));
1118             } while (++position < limit);
1119
1120             return JSValue::encode(result);
1121         }
1122
1123         // 3 cases:
1124         // -separator length == 1, 8 bits
1125         // -separator length == 1, 16 bits
1126         // -separator length > 1
1127         StringImpl* stringImpl = input.impl();
1128         StringImpl* separatorImpl = separator.impl();
1129         size_t separatorLength = separatorImpl->length();
1130
1131         if (separatorLength == 1) {
1132             UChar separatorCharacter;
1133             if (separatorImpl->is8Bit())
1134                 separatorCharacter = separatorImpl->characters8()[0];
1135             else
1136                 separatorCharacter = separatorImpl->characters16()[0];
1137
1138             if (stringImpl->is8Bit()) {
1139                 if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
1140                     return JSValue::encode(result);
1141             } else {
1142                 if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
1143                     return JSValue::encode(result);
1144             }
1145         } else {
1146             // 12. Let q = p.
1147             size_t matchPosition;
1148             // 13. Repeat, while q != s
1149             //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1150             //   b. If z is failure, then let q = q+1.
1151             //   c. Else, z is not failure
1152             while ((matchPosition = stringImpl->find(separatorImpl, position)) != notFound) {
1153                 // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1154                 //    through q (exclusive).
1155                 // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1156                 //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1157                 result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
1158                 // 3. Increment lengthA by 1.
1159                 // 4. If lengthA == lim, return A.
1160                 if (++resultLength == limit)
1161                     return JSValue::encode(result);
1162
1163                 // 5. Let p = e.
1164                 // 8. Let q = p.
1165                 position = matchPosition + separator.length();
1166             }
1167         }
1168     }
1169
1170     // 14. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1171     //     through s (exclusive).
1172     // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
1173     //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1174     result->putDirectIndex(exec, resultLength++, jsSubstring(exec, input, position, input.length() - position));
1175
1176     // 16. Return A.
1177     return JSValue::encode(result);
1178 }
1179
1180 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
1181 {
1182     JSValue thisValue = exec->hostThisValue();
1183     if (!checkObjectCoercible(thisValue))
1184         return throwVMTypeError(exec);
1185     unsigned len;
1186     JSString* jsString = 0;
1187     String uString;
1188     if (thisValue.isString()) {
1189         jsString = jsCast<JSString*>(thisValue.asCell());
1190         len = jsString->length();
1191     } else {
1192         uString = thisValue.toString(exec)->value(exec);
1193         if (exec->hadException())
1194             return JSValue::encode(jsUndefined());
1195         len = uString.length();
1196     }
1197
1198     JSValue a0 = exec->argument(0);
1199     JSValue a1 = exec->argument(1);
1200
1201     double start = a0.toInteger(exec);
1202     double length = a1.isUndefined() ? len : a1.toInteger(exec);
1203     if (start >= len || length <= 0)
1204         return JSValue::encode(jsEmptyString(exec));
1205     if (start < 0) {
1206         start += len;
1207         if (start < 0)
1208             start = 0;
1209     }
1210     if (start + length > len)
1211         length = len - start;
1212     unsigned substringStart = static_cast<unsigned>(start);
1213     unsigned substringLength = static_cast<unsigned>(length);
1214     if (jsString)
1215         return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1216     return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
1217 }
1218
1219 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
1220 {
1221     JSValue thisValue = exec->hostThisValue();
1222     if (!checkObjectCoercible(thisValue))
1223         return throwVMTypeError(exec);
1224
1225     JSString* jsString = thisValue.toString(exec);
1226     if (exec->hadException())
1227         return JSValue::encode(jsUndefined());
1228
1229     JSValue a0 = exec->argument(0);
1230     JSValue a1 = exec->argument(1);
1231     int len = jsString->length();
1232
1233     double start = a0.toNumber(exec);
1234     double end;
1235     if (!(start >= 0)) // check for negative values or NaN
1236         start = 0;
1237     else if (start > len)
1238         start = len;
1239     if (a1.isUndefined())
1240         end = len;
1241     else { 
1242         end = a1.toNumber(exec);
1243         if (!(end >= 0)) // check for negative values or NaN
1244             end = 0;
1245         else if (end > len)
1246             end = len;
1247     }
1248     if (start > end) {
1249         double temp = end;
1250         end = start;
1251         start = temp;
1252     }
1253     unsigned substringStart = static_cast<unsigned>(start);
1254     unsigned substringLength = static_cast<unsigned>(end) - substringStart;
1255     return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1256 }
1257
1258 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
1259 {
1260     JSValue thisValue = exec->hostThisValue();
1261     if (!checkObjectCoercible(thisValue))
1262         return throwVMTypeError(exec);
1263     JSString* sVal = thisValue.toString(exec);
1264     const String& s = sVal->value(exec);
1265
1266     int sSize = s.length();
1267     if (!sSize)
1268         return JSValue::encode(sVal);
1269
1270     StringImpl* ourImpl = s.impl();
1271     RefPtr<StringImpl> lower = ourImpl->lower();
1272     if (ourImpl == lower)
1273         return JSValue::encode(sVal);
1274     return JSValue::encode(jsString(exec, String(lower.release())));
1275 }
1276
1277 EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
1278 {
1279     JSValue thisValue = exec->hostThisValue();
1280     if (!checkObjectCoercible(thisValue))
1281         return throwVMTypeError(exec);
1282     JSString* sVal = thisValue.toString(exec);
1283     const String& s = sVal->value(exec);
1284
1285     int sSize = s.length();
1286     if (!sSize)
1287         return JSValue::encode(sVal);
1288
1289     StringImpl* sImpl = s.impl();
1290     RefPtr<StringImpl> upper = sImpl->upper();
1291     if (sImpl == upper)
1292         return JSValue::encode(sVal);
1293     return JSValue::encode(jsString(exec, String(upper.release())));
1294 }
1295
1296 EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
1297 {
1298     JSValue thisValue = exec->hostThisValue();
1299     if (!checkObjectCoercible(thisValue))
1300         return throwVMTypeError(exec);
1301     String s = thisValue.toString(exec)->value(exec);
1302
1303     JSValue a0 = exec->argument(0);
1304     return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec)->value(exec))));
1305 }
1306
1307 EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
1308 {
1309     JSValue thisValue = exec->hostThisValue();
1310     if (!checkObjectCoercible(thisValue))
1311         return throwVMTypeError(exec);
1312     String s = thisValue.toString(exec)->value(exec);
1313     return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
1314 }
1315
1316 EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
1317 {
1318     JSValue thisValue = exec->hostThisValue();
1319     if (!checkObjectCoercible(thisValue))
1320         return throwVMTypeError(exec);
1321     String s = thisValue.toString(exec)->value(exec);
1322     return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
1323 }
1324
1325 EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
1326 {
1327     JSValue thisValue = exec->hostThisValue();
1328     if (!checkObjectCoercible(thisValue))
1329         return throwVMTypeError(exec);
1330     String s = thisValue.toString(exec)->value(exec);
1331     return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
1332 }
1333
1334 EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
1335 {
1336     JSValue thisValue = exec->hostThisValue();
1337     if (!checkObjectCoercible(thisValue))
1338         return throwVMTypeError(exec);
1339     String s = thisValue.toString(exec)->value(exec);
1340     return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
1341 }
1342
1343 EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
1344 {
1345     JSValue thisValue = exec->hostThisValue();
1346     if (!checkObjectCoercible(thisValue))
1347         return throwVMTypeError(exec);
1348     String s = thisValue.toString(exec)->value(exec);
1349     return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
1350 }
1351
1352 EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
1353 {
1354     JSValue thisValue = exec->hostThisValue();
1355     if (!checkObjectCoercible(thisValue))
1356         return throwVMTypeError(exec);
1357     String s = thisValue.toString(exec)->value(exec);
1358     return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
1359 }
1360
1361 EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
1362 {
1363     JSValue thisValue = exec->hostThisValue();
1364     if (!checkObjectCoercible(thisValue))
1365         return throwVMTypeError(exec);
1366     String s = thisValue.toString(exec)->value(exec);
1367     return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
1368 }
1369
1370 EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
1371 {
1372     JSValue thisValue = exec->hostThisValue();
1373     if (!checkObjectCoercible(thisValue))
1374         return throwVMTypeError(exec);
1375     String s = thisValue.toString(exec)->value(exec);
1376     return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
1377 }
1378
1379 EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
1380 {
1381     JSValue thisValue = exec->hostThisValue();
1382     if (!checkObjectCoercible(thisValue))
1383         return throwVMTypeError(exec);
1384     String s = thisValue.toString(exec)->value(exec);
1385     return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
1386 }
1387
1388 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
1389 {
1390     JSValue thisValue = exec->hostThisValue();
1391     if (!checkObjectCoercible(thisValue))
1392         return throwVMTypeError(exec);
1393     String s = thisValue.toString(exec)->value(exec);
1394     JSValue a0 = exec->argument(0);
1395     String color = a0.toWTFString(exec);
1396     color.replaceWithLiteral('"', "&quot;");
1397
1398     return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>"));
1399 }
1400
1401 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
1402 {
1403     JSValue thisValue = exec->hostThisValue();
1404     if (!checkObjectCoercible(thisValue))
1405         return throwVMTypeError(exec);
1406     String s = thisValue.toString(exec)->value(exec);
1407     JSValue a0 = exec->argument(0);
1408
1409     uint32_t smallInteger;
1410     if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
1411         unsigned stringSize = s.length();
1412         unsigned bufferSize = 22 + stringSize;
1413         UChar* buffer;
1414         PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1415         if (!impl)
1416             return JSValue::encode(jsUndefined());
1417         buffer[0] = '<';
1418         buffer[1] = 'f';
1419         buffer[2] = 'o';
1420         buffer[3] = 'n';
1421         buffer[4] = 't';
1422         buffer[5] = ' ';
1423         buffer[6] = 's';
1424         buffer[7] = 'i';
1425         buffer[8] = 'z';
1426         buffer[9] = 'e';
1427         buffer[10] = '=';
1428         buffer[11] = '"';
1429         buffer[12] = '0' + smallInteger;
1430         buffer[13] = '"';
1431         buffer[14] = '>';
1432         memcpy(&buffer[15], s.characters(), stringSize * sizeof(UChar));
1433         buffer[15 + stringSize] = '<';
1434         buffer[16 + stringSize] = '/';
1435         buffer[17 + stringSize] = 'f';
1436         buffer[18 + stringSize] = 'o';
1437         buffer[19 + stringSize] = 'n';
1438         buffer[20 + stringSize] = 't';
1439         buffer[21 + stringSize] = '>';
1440         return JSValue::encode(jsNontrivialString(exec, impl));
1441     }
1442
1443     String fontSize = a0.toWTFString(exec);
1444     fontSize.replaceWithLiteral('"', "&quot;");
1445
1446     return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>"));
1447 }
1448
1449 EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
1450 {
1451     JSValue thisValue = exec->hostThisValue();
1452     if (!checkObjectCoercible(thisValue))
1453         return throwVMTypeError(exec);
1454     String s = thisValue.toString(exec)->value(exec);
1455     JSValue a0 = exec->argument(0);
1456     String anchor = a0.toWTFString(exec);
1457     anchor.replaceWithLiteral('"', "&quot;");
1458
1459     return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>"));
1460 }
1461
1462 EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
1463 {
1464     JSValue thisValue = exec->hostThisValue();
1465     if (!checkObjectCoercible(thisValue))
1466         return throwVMTypeError(exec);
1467     String s = thisValue.toString(exec)->value(exec);
1468     JSValue a0 = exec->argument(0);
1469     String linkText = a0.toWTFString(exec);
1470     linkText.replaceWithLiteral('"', "&quot;");
1471
1472     unsigned linkTextSize = linkText.length();
1473     unsigned stringSize = s.length();
1474     unsigned bufferSize = 15 + linkTextSize + stringSize;
1475     UChar* buffer;
1476     PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1477     if (!impl)
1478         return JSValue::encode(jsUndefined());
1479     buffer[0] = '<';
1480     buffer[1] = 'a';
1481     buffer[2] = ' ';
1482     buffer[3] = 'h';
1483     buffer[4] = 'r';
1484     buffer[5] = 'e';
1485     buffer[6] = 'f';
1486     buffer[7] = '=';
1487     buffer[8] = '"';
1488     memcpy(&buffer[9], linkText.characters(), linkTextSize * sizeof(UChar));
1489     buffer[9 + linkTextSize] = '"';
1490     buffer[10 + linkTextSize] = '>';
1491     memcpy(&buffer[11 + linkTextSize], s.characters(), stringSize * sizeof(UChar));
1492     buffer[11 + linkTextSize + stringSize] = '<';
1493     buffer[12 + linkTextSize + stringSize] = '/';
1494     buffer[13 + linkTextSize + stringSize] = 'a';
1495     buffer[14 + linkTextSize + stringSize] = '>';
1496     return JSValue::encode(jsNontrivialString(exec, impl));
1497 }
1498
1499 enum {
1500     TrimLeft = 1,
1501     TrimRight = 2
1502 };
1503
1504 static inline bool isTrimWhitespace(UChar c)
1505 {
1506     return isStrWhiteSpace(c) || c == 0x200b;
1507 }
1508
1509 static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
1510 {
1511     if (!checkObjectCoercible(thisValue))
1512         return throwTypeError(exec);
1513     String str = thisValue.toString(exec)->value(exec);
1514     unsigned left = 0;
1515     if (trimKind & TrimLeft) {
1516         while (left < str.length() && isTrimWhitespace(str[left]))
1517             left++;
1518     }
1519     unsigned right = str.length();
1520     if (trimKind & TrimRight) {
1521         while (right > left && isTrimWhitespace(str[right - 1]))
1522             right--;
1523     }
1524
1525     // Don't gc allocate a new string if we don't have to.
1526     if (left == 0 && right == str.length() && thisValue.isString())
1527         return thisValue;
1528
1529     return jsString(exec, str.substringSharingImpl(left, right - left));
1530 }
1531
1532 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
1533 {
1534     JSValue thisValue = exec->hostThisValue();
1535     return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
1536 }
1537
1538 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
1539 {
1540     JSValue thisValue = exec->hostThisValue();
1541     return JSValue::encode(trimString(exec, thisValue, TrimLeft));
1542 }
1543
1544 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
1545 {
1546     JSValue thisValue = exec->hostThisValue();
1547     return JSValue::encode(trimString(exec, thisValue, TrimRight));
1548 }
1549     
1550     
1551 } // namespace JSC