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