Make JSString::SafeView less of a footgun.
[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  *  Copyright (C) 2015 Jordan Harband (ljharb@gmail.com)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include "config.h"
24 #include "StringPrototype.h"
25
26 #include "ButterflyInlines.h"
27 #include "CachedCall.h"
28 #include "CopiedSpaceInlines.h"
29 #include "Error.h"
30 #include "Executable.h"
31 #include "IntlObject.h"
32 #include "JSCInlines.h"
33 #include "JSGlobalObjectFunctions.h"
34 #include "JSArray.h"
35 #include "JSFunction.h"
36 #include "JSStringBuilder.h"
37 #include "JSStringIterator.h"
38 #include "Lookup.h"
39 #include "ObjectPrototype.h"
40 #include "PropertyNameArray.h"
41 #include "RegExpCache.h"
42 #include "RegExpConstructor.h"
43 #include "RegExpMatchesArray.h"
44 #include "RegExpObject.h"
45 #include <algorithm>
46 #include <unicode/uconfig.h>
47 #include <unicode/unorm.h>
48 #include <unicode/ustring.h>
49 #include <wtf/ASCIICType.h>
50 #include <wtf/MathExtras.h>
51 #include <wtf/text/StringView.h>
52 #include <wtf/unicode/Collator.h>
53
54 using namespace WTF;
55
56 namespace JSC {
57
58 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringPrototype);
59
60 EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
61 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
62 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
63 EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState*);
64 EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
65 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
66 EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
67 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
68 EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState*);
69 EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
70 EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
71 EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
72 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
73 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
74 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
75 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
76 EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
77 EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
78 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleLowerCase(ExecState*);
79 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleUpperCase(ExecState*);
80 EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
81 EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
82 EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
83 EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
84 EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
85 EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
86 EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
87 EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
88 EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
89 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
90 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
91 EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
92 EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
93 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
94 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
95 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
96 EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState*);
97 EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState*);
98 EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState*);
99 EncodedJSValue JSC_HOST_CALL stringProtoFuncNormalize(ExecState*);
100 EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState*);
101
102 const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, CREATE_METHOD_TABLE(StringPrototype) };
103
104 // ECMA 15.5.4
105 StringPrototype::StringPrototype(VM& vm, Structure* structure)
106     : StringObject(vm, structure)
107 {
108 }
109
110 void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSString* nameAndMessage)
111 {
112     Base::finishCreation(vm, nameAndMessage);
113     ASSERT(inherits(info()));
114
115     JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
116     JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
117     JSC_NATIVE_INTRINSIC_FUNCTION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
118     JSC_NATIVE_INTRINSIC_FUNCTION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
119     JSC_NATIVE_FUNCTION("codePointAt", stringProtoFuncCodePointAt, DontEnum, 1);
120     JSC_NATIVE_FUNCTION("concat", stringProtoFuncConcat, DontEnum, 1);
121     JSC_NATIVE_FUNCTION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
122     JSC_NATIVE_FUNCTION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
123     JSC_NATIVE_FUNCTION("match", stringProtoFuncMatch, DontEnum, 1);
124     JSC_NATIVE_FUNCTION("repeat", stringProtoFuncRepeat, DontEnum, 1);
125     JSC_NATIVE_FUNCTION("replace", stringProtoFuncReplace, DontEnum, 2);
126     JSC_NATIVE_FUNCTION("search", stringProtoFuncSearch, DontEnum, 1);
127     JSC_NATIVE_FUNCTION("slice", stringProtoFuncSlice, DontEnum, 2);
128     JSC_NATIVE_FUNCTION("split", stringProtoFuncSplit, DontEnum, 2);
129     JSC_NATIVE_FUNCTION("substr", stringProtoFuncSubstr, DontEnum, 2);
130     JSC_NATIVE_FUNCTION("substring", stringProtoFuncSubstring, DontEnum, 2);
131     JSC_NATIVE_FUNCTION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
132     JSC_NATIVE_FUNCTION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
133     JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
134 #if ENABLE(INTL)
135     JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLocaleLowerCase, DontEnum, 0);
136     JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToLocaleUpperCase, DontEnum, 0);
137 #else
138     JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
139     JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
140 #endif
141     JSC_NATIVE_FUNCTION("big", stringProtoFuncBig, DontEnum, 0);
142     JSC_NATIVE_FUNCTION("small", stringProtoFuncSmall, DontEnum, 0);
143     JSC_NATIVE_FUNCTION("blink", stringProtoFuncBlink, DontEnum, 0);
144     JSC_NATIVE_FUNCTION("bold", stringProtoFuncBold, DontEnum, 0);
145     JSC_NATIVE_FUNCTION("fixed", stringProtoFuncFixed, DontEnum, 0);
146     JSC_NATIVE_FUNCTION("italics", stringProtoFuncItalics, DontEnum, 0);
147     JSC_NATIVE_FUNCTION("strike", stringProtoFuncStrike, DontEnum, 0);
148     JSC_NATIVE_FUNCTION("sub", stringProtoFuncSub, DontEnum, 0);
149     JSC_NATIVE_FUNCTION("sup", stringProtoFuncSup, DontEnum, 0);
150     JSC_NATIVE_FUNCTION("fontcolor", stringProtoFuncFontcolor, DontEnum, 1);
151     JSC_NATIVE_FUNCTION("fontsize", stringProtoFuncFontsize, DontEnum, 1);
152     JSC_NATIVE_FUNCTION("anchor", stringProtoFuncAnchor, DontEnum, 1);
153     JSC_NATIVE_FUNCTION("link", stringProtoFuncLink, DontEnum, 1);
154     JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0);
155     JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
156     JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
157     JSC_NATIVE_FUNCTION("startsWith", stringProtoFuncStartsWith, DontEnum, 1);
158     JSC_NATIVE_FUNCTION("endsWith", stringProtoFuncEndsWith, DontEnum, 1);
159     JSC_NATIVE_FUNCTION("includes", stringProtoFuncIncludes, DontEnum, 1);
160     JSC_NATIVE_FUNCTION("normalize", stringProtoFuncNormalize, DontEnum, 1);
161     JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorSymbol, stringProtoFuncIterator, DontEnum, 0);
162
163     JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->charCodeAtPrivateName, stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
164
165     // The constructor will be added later, after StringConstructor has been built
166     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
167 }
168
169 StringPrototype* StringPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
170 {
171     JSString* empty = jsEmptyString(&vm);
172     StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(vm.heap)) StringPrototype(vm, structure);
173     prototype->finishCreation(vm, globalObject, empty);
174     return prototype;
175 }
176
177 // ------------------------------ Functions --------------------------
178
179 // Helper for producing a JSString for 'string', where 'string' was been produced by
180 // calling ToString on 'originalValue'. In cases where 'originalValue' already was a
181 // string primitive we can just use this, otherwise we need to allocate a new JSString.
182 static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue, const String& string)
183 {
184     if (originalValue.isString()) {
185         ASSERT(asString(originalValue)->value(exec) == string);
186         return asString(originalValue);
187     }
188     return jsString(exec, string);
189 }
190
191 // Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
192 static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
193 {
194     if (originalValue.isString()) {
195         ASSERT(asString(originalValue)->value(exec) == string);
196         return jsSubstring(exec, asString(originalValue), offset, length);
197     }
198     return jsSubstring(exec, string, offset, length);
199 }
200
201 static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i)
202 {
203     StringBuilder substitutedReplacement;
204     int offset = 0;
205     do {
206         if (i + 1 == replacement.length())
207             break;
208
209         UChar ref = replacement[i + 1];
210         if (ref == '$') {
211             // "$$" -> "$"
212             ++i;
213             substitutedReplacement.append(replacement.substring(offset, i - offset));
214             offset = i + 1;
215             continue;
216         }
217
218         int backrefStart;
219         int backrefLength;
220         int advance = 0;
221         if (ref == '&') {
222             backrefStart = ovector[0];
223             backrefLength = ovector[1] - backrefStart;
224         } else if (ref == '`') {
225             backrefStart = 0;
226             backrefLength = ovector[0];
227         } else if (ref == '\'') {
228             backrefStart = ovector[1];
229             backrefLength = source.length() - backrefStart;
230         } else if (reg && ref >= '0' && ref <= '9') {
231             // 1- and 2-digit back references are allowed
232             unsigned backrefIndex = ref - '0';
233             if (backrefIndex > reg->numSubpatterns())
234                 continue;
235             if (replacement.length() > i + 2) {
236                 ref = replacement[i + 2];
237                 if (ref >= '0' && ref <= '9') {
238                     backrefIndex = 10 * backrefIndex + ref - '0';
239                     if (backrefIndex > reg->numSubpatterns())
240                         backrefIndex = backrefIndex / 10;   // Fall back to the 1-digit reference
241                     else
242                         advance = 1;
243                 }
244             }
245             if (!backrefIndex)
246                 continue;
247             backrefStart = ovector[2 * backrefIndex];
248             backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
249         } else
250             continue;
251
252         if (i - offset)
253             substitutedReplacement.append(replacement.substring(offset, i - offset));
254         i += 1 + advance;
255         offset = i + 1;
256         if (backrefStart >= 0)
257             substitutedReplacement.append(source.substring(backrefStart, backrefLength));
258     } while ((i = replacement.find('$', i + 1)) != notFound);
259
260     if (replacement.length() - offset)
261         substitutedReplacement.append(replacement.substring(offset));
262
263     return substitutedReplacement.toString();
264 }
265
266 static inline String substituteBackreferences(const String& replacement, StringView source, const int* ovector, RegExp* reg)
267 {
268     size_t i = replacement.find('$');
269     if (UNLIKELY(i != notFound))
270         return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
271
272     return replacement;
273 }
274
275 struct StringRange {
276     StringRange(int pos, int len)
277         : position(pos)
278         , length(len)
279     {
280     }
281
282     StringRange()
283     {
284     }
285
286     int position;
287     int length;
288 };
289
290 static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourceVal, const String& source, const StringRange* substringRanges, int rangeCount)
291 {
292     if (rangeCount == 1) {
293         int sourceSize = source.length();
294         int position = substringRanges[0].position;
295         int length = substringRanges[0].length;
296         if (position <= 0 && length >= sourceSize)
297             return sourceVal;
298         // We could call String::substringSharingImpl(), but this would result in redundant checks.
299         return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length)));
300     }
301
302     int totalLength = 0;
303     for (int i = 0; i < rangeCount; i++)
304         totalLength += substringRanges[i].length;
305
306     if (!totalLength)
307         return jsEmptyString(exec);
308
309     if (source.is8Bit()) {
310         LChar* buffer;
311         const LChar* sourceData = source.characters8();
312         RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
313         if (!impl)
314             return throwOutOfMemoryError(exec);
315
316         int bufferPos = 0;
317         for (int i = 0; i < rangeCount; i++) {
318             if (int srcLen = substringRanges[i].length) {
319                 StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
320                 bufferPos += srcLen;
321             }
322         }
323
324         return jsString(exec, impl.release());
325     }
326
327     UChar* buffer;
328     const UChar* sourceData = source.characters16();
329
330     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
331     if (!impl)
332         return throwOutOfMemoryError(exec);
333
334     int bufferPos = 0;
335     for (int i = 0; i < rangeCount; i++) {
336         if (int srcLen = substringRanges[i].length) {
337             StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
338             bufferPos += srcLen;
339         }
340     }
341
342     return jsString(exec, impl.release());
343 }
344
345 static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const String& source, const StringRange* substringRanges, int rangeCount, const String* separators, int separatorCount)
346 {
347     if (rangeCount == 1 && separatorCount == 0) {
348         int sourceSize = source.length();
349         int position = substringRanges[0].position;
350         int length = substringRanges[0].length;
351         if (position <= 0 && length >= sourceSize)
352             return sourceVal;
353         // We could call String::substringSharingImpl(), but this would result in redundant checks.
354         return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length)));
355     }
356
357     Checked<int, RecordOverflow> totalLength = 0;
358     bool allSeparators8Bit = true;
359     for (int i = 0; i < rangeCount; i++)
360         totalLength += substringRanges[i].length;
361     for (int i = 0; i < separatorCount; i++) {
362         totalLength += separators[i].length();
363         if (separators[i].length() && !separators[i].is8Bit())
364             allSeparators8Bit = false;
365     }
366     if (totalLength.hasOverflowed())
367         return throwOutOfMemoryError(exec);
368
369     if (!totalLength)
370         return jsEmptyString(exec);
371
372     if (source.is8Bit() && allSeparators8Bit) {
373         LChar* buffer;
374         const LChar* sourceData = source.characters8();
375
376         RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer);
377         if (!impl)
378             return throwOutOfMemoryError(exec);
379
380         int maxCount = std::max(rangeCount, separatorCount);
381         int bufferPos = 0;
382         for (int i = 0; i < maxCount; i++) {
383             if (i < rangeCount) {
384                 if (int srcLen = substringRanges[i].length) {
385                     StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
386                     bufferPos += srcLen;
387                 }
388             }
389             if (i < separatorCount) {
390                 if (int sepLen = separators[i].length()) {
391                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
392                     bufferPos += sepLen;
393                 }
394             }
395         }        
396
397         return jsString(exec, impl.release());
398     }
399
400     UChar* buffer;
401     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength.unsafeGet(), buffer);
402     if (!impl)
403         return throwOutOfMemoryError(exec);
404
405     int maxCount = std::max(rangeCount, separatorCount);
406     int bufferPos = 0;
407     for (int i = 0; i < maxCount; i++) {
408         if (i < rangeCount) {
409             if (int srcLen = substringRanges[i].length) {
410                 if (source.is8Bit())
411                     StringImpl::copyChars(buffer + bufferPos, source.characters8() + substringRanges[i].position, srcLen);
412                 else
413                     StringImpl::copyChars(buffer + bufferPos, source.characters16() + substringRanges[i].position, srcLen);
414                 bufferPos += srcLen;
415             }
416         }
417         if (i < separatorCount) {
418             if (int sepLen = separators[i].length()) {
419                 if (separators[i].is8Bit())
420                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
421                 else
422                     StringImpl::copyChars(buffer + bufferPos, separators[i].characters16(), sepLen);
423                 bufferPos += sepLen;
424             }
425         }
426     }
427
428     return jsString(exec, impl.release());
429 }
430
431 static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
432 {
433     size_t lastIndex = 0;
434     unsigned startPosition = 0;
435
436     Vector<StringRange, 16> sourceRanges;
437     VM* vm = &exec->vm();
438     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
439     unsigned sourceLen = source.length();
440
441     while (true) {
442         MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition);
443         if (!result)
444             break;
445
446         if (lastIndex < result.start)
447             sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
448
449         lastIndex = result.end;
450         startPosition = lastIndex;
451
452         // special case of empty match
453         if (result.empty()) {
454             startPosition++;
455             if (startPosition > sourceLen)
456                 break;
457         }
458     }
459
460     if (!lastIndex)
461         return JSValue::encode(string);
462
463     if (static_cast<unsigned>(lastIndex) < sourceLen)
464         sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
465
466     return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
467 }
468
469 static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
470 {
471     JSValue replaceValue = exec->argument(1);
472     String replacementString;
473     CallData callData;
474     CallType callType = getCallData(replaceValue, callData);
475     if (callType == CallTypeNone)
476         replacementString = replaceValue.toString(exec)->value(exec);
477
478     const String& source = string->value(exec);
479     unsigned sourceLen = source.length();
480     if (exec->hadException())
481         return JSValue::encode(JSValue());
482     RegExpObject* regExpObject = asRegExpObject(searchValue);
483     RegExp* regExp = regExpObject->regExp();
484     bool global = regExp->global();
485
486     if (global) {
487         // ES5.1 15.5.4.10 step 8.a.
488         regExpObject->setLastIndex(exec, 0);
489         if (exec->hadException())
490             return JSValue::encode(JSValue());
491
492         if (callType == CallTypeNone && !replacementString.length())
493             return removeUsingRegExpSearch(exec, string, source, regExp);
494     }
495
496     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
497
498     size_t lastIndex = 0;
499     unsigned startPosition = 0;
500
501     Vector<StringRange, 16> sourceRanges;
502     Vector<String, 16> replacements;
503
504     // This is either a loop (if global is set) or a one-way (if not).
505     if (global && callType == CallTypeJS) {
506         // regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
507         int argCount = regExp->numSubpatterns() + 1 + 2;
508         JSFunction* func = jsCast<JSFunction*>(replaceValue);
509         CachedCall cachedCall(exec, func, argCount);
510         if (exec->hadException())
511             return JSValue::encode(jsNull());
512         VM* vm = &exec->vm();
513         if (source.is8Bit()) {
514             while (true) {
515                 int* ovector;
516                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
517                 if (!result)
518                     break;
519
520                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
521
522                 unsigned i = 0;
523                 for (; i < regExp->numSubpatterns() + 1; ++i) {
524                     int matchStart = ovector[i * 2];
525                     int matchLen = ovector[i * 2 + 1] - matchStart;
526
527                     if (matchStart < 0)
528                         cachedCall.setArgument(i, jsUndefined());
529                     else
530                         cachedCall.setArgument(i, jsSubstring8(vm, source, matchStart, matchLen));
531                 }
532
533                 cachedCall.setArgument(i++, jsNumber(result.start));
534                 cachedCall.setArgument(i++, string);
535
536                 cachedCall.setThis(jsUndefined());
537                 JSValue jsResult = cachedCall.call();
538                 replacements.append(jsResult.toString(exec)->value(exec));
539                 if (exec->hadException())
540                     break;
541
542                 lastIndex = result.end;
543                 startPosition = lastIndex;
544
545                 // special case of empty match
546                 if (result.empty()) {
547                     startPosition++;
548                     if (startPosition > sourceLen)
549                         break;
550                 }
551             }
552         } else {
553             while (true) {
554                 int* ovector;
555                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
556                 if (!result)
557                     break;
558
559                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
560
561                 unsigned i = 0;
562                 for (; i < regExp->numSubpatterns() + 1; ++i) {
563                     int matchStart = ovector[i * 2];
564                     int matchLen = ovector[i * 2 + 1] - matchStart;
565
566                     if (matchStart < 0)
567                         cachedCall.setArgument(i, jsUndefined());
568                     else
569                         cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen));
570                 }
571
572                 cachedCall.setArgument(i++, jsNumber(result.start));
573                 cachedCall.setArgument(i++, string);
574
575                 cachedCall.setThis(jsUndefined());
576                 JSValue jsResult = cachedCall.call();
577                 replacements.append(jsResult.toString(exec)->value(exec));
578                 if (exec->hadException())
579                     break;
580
581                 lastIndex = result.end;
582                 startPosition = lastIndex;
583
584                 // special case of empty match
585                 if (result.empty()) {
586                     startPosition++;
587                     if (startPosition > sourceLen)
588                         break;
589                 }
590             }
591         }
592     } else {
593         VM* vm = &exec->vm();
594         do {
595             int* ovector;
596             MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
597             if (!result)
598                 break;
599
600             if (callType != CallTypeNone) {
601                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
602
603                 MarkedArgumentBuffer args;
604
605                 for (unsigned i = 0; i < regExp->numSubpatterns() + 1; ++i) {
606                     int matchStart = ovector[i * 2];
607                     int matchLen = ovector[i * 2 + 1] - matchStart;
608
609                     if (matchStart < 0)
610                         args.append(jsUndefined());
611                     else
612                         args.append(jsSubstring(exec, source, matchStart, matchLen));
613                 }
614
615                 args.append(jsNumber(result.start));
616                 args.append(string);
617
618                 replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec));
619                 if (exec->hadException())
620                     break;
621             } else {
622                 int replLen = replacementString.length();
623                 if (lastIndex < result.start || replLen) {
624                     sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
625
626                     if (replLen)
627                         replacements.append(substituteBackreferences(replacementString, source, ovector, regExp));
628                     else
629                         replacements.append(String());
630                 }
631             }
632
633             lastIndex = result.end;
634             startPosition = lastIndex;
635
636             // special case of empty match
637             if (result.empty()) {
638                 startPosition++;
639                 if (startPosition > sourceLen)
640                     break;
641             }
642         } while (global);
643     }
644
645     if (!lastIndex && replacements.isEmpty())
646         return JSValue::encode(string);
647
648     if (static_cast<unsigned>(lastIndex) < sourceLen)
649         sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
650
651     return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
652 }
653
654 static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
655 {
656     const String& string = jsString->value(exec);
657     String searchString = searchValue.toString(exec)->value(exec);
658     if (exec->hadException())
659         return JSValue::encode(jsUndefined());
660
661     size_t matchStart = string.find(searchString);
662
663     if (matchStart == notFound)
664         return JSValue::encode(jsString);
665
666     JSValue replaceValue = exec->argument(1);
667     CallData callData;
668     CallType callType = getCallData(replaceValue, callData);
669     if (callType != CallTypeNone) {
670         MarkedArgumentBuffer args;
671         args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
672         args.append(jsNumber(matchStart));
673         args.append(jsString);
674         replaceValue = call(exec, replaceValue, callType, callData, jsUndefined(), args);
675         if (exec->hadException())
676             return JSValue::encode(jsUndefined());
677     }
678
679     String replaceString = replaceValue.toString(exec)->value(exec);
680     if (exec->hadException())
681         return JSValue::encode(jsUndefined());
682
683     StringImpl* stringImpl = string.impl();
684     String leftPart(StringImpl::createSubstringSharingImpl(stringImpl, 0, matchStart));
685
686     size_t matchEnd = matchStart + searchString.impl()->length();
687     int ovector[2] = { static_cast<int>(matchStart),  static_cast<int>(matchEnd)};
688     String middlePart = substituteBackreferences(replaceString, string, ovector, 0);
689
690     size_t leftLength = stringImpl->length() - matchEnd;
691     String rightPart(StringImpl::createSubstringSharingImpl(stringImpl, matchEnd, leftLength));
692     return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart));
693 }
694
695 static inline bool checkObjectCoercible(JSValue thisValue)
696 {
697     if (thisValue.isString())
698         return true;
699
700     if (thisValue.isUndefinedOrNull())
701         return false;
702
703     if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isEnvironmentRecord())
704         return false;
705
706     return true;
707 }
708
709 template <typename CharacterType>
710 static inline JSValue repeatCharacter(ExecState* exec, CharacterType character, unsigned repeatCount)
711 {
712     CharacterType* buffer = nullptr;
713     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(repeatCount, buffer);
714     if (!impl)
715         return throwOutOfMemoryError(exec);
716
717     std::fill_n(buffer, repeatCount, character);
718
719     return jsString(exec, impl.release());
720 }
721
722 EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec)
723 {
724     JSValue thisValue = exec->thisValue();
725     if (!checkObjectCoercible(thisValue))
726         return throwVMTypeError(exec);
727
728     JSString* string = thisValue.toString(exec);
729     if (exec->hadException())
730         return JSValue::encode(jsUndefined());
731
732     double repeatCountDouble = exec->argument(0).toInteger(exec);
733     if (exec->hadException())
734         return JSValue::encode(jsUndefined());
735     if (repeatCountDouble < 0 || std::isinf(repeatCountDouble))
736         return throwVMError(exec, createRangeError(exec, ASCIILiteral("repeat() argument must be greater than or equal to 0 and not be infinity")));
737
738     VM& vm = exec->vm();
739
740     if (!string->length() || !repeatCountDouble)
741         return JSValue::encode(jsEmptyString(&vm));
742
743     if (repeatCountDouble == 1)
744         return JSValue::encode(string);
745
746     // JSString requires the limitation that its length is in the range of int32_t.
747     if (repeatCountDouble > std::numeric_limits<int32_t>::max() / string->length())
748         return JSValue::encode(throwOutOfMemoryError(exec));
749     unsigned repeatCount = static_cast<unsigned>(repeatCountDouble);
750
751     // For a string which length is small, instead of creating ropes,
752     // allocating a sequential buffer and fill with the repeated string for efficiency.
753     if (string->length() == 1) {
754         String repeatedString = string->value(exec);
755         UChar character = repeatedString.at(0);
756         if (!(character & ~0xff))
757             return JSValue::encode(repeatCharacter(exec, static_cast<LChar>(character), repeatCount));
758         return JSValue::encode(repeatCharacter(exec, character, repeatCount));
759     }
760
761     JSRopeString::RopeBuilder ropeBuilder(vm);
762     for (unsigned i = 0; i < repeatCount; ++i) {
763         if (!ropeBuilder.append(string))
764             return JSValue::encode(throwOutOfMemoryError(exec));
765     }
766     return JSValue::encode(ropeBuilder.release());
767 }
768
769 EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
770 {
771     JSValue thisValue = exec->thisValue();
772     if (!checkObjectCoercible(thisValue))
773         return throwVMTypeError(exec);
774     JSString* string = thisValue.toString(exec);
775     JSValue searchValue = exec->argument(0);
776
777     if (searchValue.inherits(RegExpObject::info()))
778         return replaceUsingRegExpSearch(exec, string, searchValue);
779     return replaceUsingStringSearch(exec, string, searchValue);
780 }
781
782 EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
783 {
784     JSValue thisValue = exec->thisValue();
785     // Also used for valueOf.
786
787     if (thisValue.isString())
788         return JSValue::encode(thisValue);
789
790     if (thisValue.inherits(StringObject::info()))
791         return JSValue::encode(asStringObject(thisValue)->internalValue());
792
793     return throwVMTypeError(exec);
794 }
795
796 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
797 {
798     JSValue thisValue = exec->thisValue();
799     if (!checkObjectCoercible(thisValue))
800         return throwVMTypeError(exec);
801     JSString::SafeView string = thisValue.toString(exec)->view(exec);
802     JSValue a0 = exec->argument(0);
803     if (a0.isUInt32()) {
804         uint32_t i = a0.asUInt32();
805         if (i < string.length())
806             return JSValue::encode(jsSingleCharacterString(exec, string[i]));
807         return JSValue::encode(jsEmptyString(exec));
808     }
809     double dpos = a0.toInteger(exec);
810     if (dpos >= 0 && dpos < string.length())
811         return JSValue::encode(jsSingleCharacterString(exec, string[static_cast<unsigned>(dpos)]));
812     return JSValue::encode(jsEmptyString(exec));
813 }
814
815 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
816 {
817     JSValue thisValue = exec->thisValue();
818     if (!checkObjectCoercible(thisValue))
819         return throwVMTypeError(exec);
820     JSString::SafeView string = thisValue.toString(exec)->view(exec);
821     JSValue a0 = exec->argument(0);
822     if (a0.isUInt32()) {
823         uint32_t i = a0.asUInt32();
824         if (i < string.length())
825             return JSValue::encode(jsNumber(string[i]));
826         return JSValue::encode(jsNaN());
827     }
828     double dpos = a0.toInteger(exec);
829     if (dpos >= 0 && dpos < string.length())
830         return JSValue::encode(jsNumber(string[static_cast<int>(dpos)]));
831     return JSValue::encode(jsNaN());
832 }
833
834 static inline UChar32 codePointAt(const String& string, unsigned position, unsigned length)
835 {
836     RELEASE_ASSERT(position < length);
837     if (string.is8Bit())
838         return string.characters8()[position];
839     UChar32 character;
840     U16_NEXT(string.characters16(), position, length, character);
841     return character;
842 }
843
844 EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec)
845 {
846     JSValue thisValue = exec->thisValue();
847     if (!checkObjectCoercible(thisValue))
848         return throwVMTypeError(exec);
849
850     String string = thisValue.toWTFString(exec);
851     unsigned length = string.length();
852
853     JSValue argument0 = exec->argument(0);
854     if (argument0.isUInt32()) {
855         unsigned position = argument0.asUInt32();
856         if (position < length)
857             return JSValue::encode(jsNumber(codePointAt(string, position, length)));
858         return JSValue::encode(jsUndefined());
859     }
860
861     if (UNLIKELY(exec->hadException()))
862         return JSValue::encode(jsUndefined());
863
864     double doublePosition = argument0.toInteger(exec);
865     if (doublePosition >= 0 && doublePosition < length)
866         return JSValue::encode(jsNumber(codePointAt(string, static_cast<unsigned>(doublePosition), length)));
867     return JSValue::encode(jsUndefined());
868 }
869
870 EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
871 {
872     JSValue thisValue = exec->thisValue();
873     if (thisValue.isString() && exec->argumentCount() == 1)
874         return JSValue::encode(jsString(exec, asString(thisValue), exec->uncheckedArgument(0).toString(exec)));
875
876     if (!checkObjectCoercible(thisValue))
877         return throwVMTypeError(exec);
878     return JSValue::encode(jsStringFromArguments(exec, thisValue));
879 }
880
881 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
882 {
883     JSValue thisValue = exec->thisValue();
884     if (!checkObjectCoercible(thisValue))
885         return throwVMTypeError(exec);
886
887     JSValue a0 = exec->argument(0);
888     JSValue a1 = exec->argument(1);
889
890     JSString* thisJSString = thisValue.toString(exec);
891     JSString* otherJSString = a0.toString(exec);
892
893     unsigned pos = 0;
894     if (!a1.isUndefined()) {
895         int len = thisJSString->length();
896         RELEASE_ASSERT(len >= 0);
897         if (a1.isUInt32())
898             pos = std::min<uint32_t>(a1.asUInt32(), len);
899         else {
900             double dpos = a1.toInteger(exec);
901             if (dpos < 0)
902                 dpos = 0;
903             else if (dpos > len)
904                 dpos = len;
905             pos = static_cast<unsigned>(dpos);
906         }
907     }
908
909     if (thisJSString->length() < otherJSString->length() + pos)
910         return JSValue::encode(jsNumber(-1));
911
912     size_t result = thisJSString->view(exec).get().find(otherJSString->view(exec).get(), pos);
913     if (result == notFound)
914         return JSValue::encode(jsNumber(-1));
915     return JSValue::encode(jsNumber(result));
916 }
917
918 EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
919 {
920     JSValue thisValue = exec->thisValue();
921     if (!checkObjectCoercible(thisValue))
922         return throwVMTypeError(exec);
923
924     JSValue a0 = exec->argument(0);
925     JSValue a1 = exec->argument(1);
926
927     JSString* thisJSString = thisValue.toString(exec);
928     unsigned len = thisJSString->length();
929     JSString* otherJSString = a0.toString(exec);
930
931     double dpos = a1.toIntegerPreserveNaN(exec);
932     unsigned startPosition;
933     if (dpos < 0)
934         startPosition = 0;
935     else if (!(dpos <= len)) // true for NaN
936         startPosition = len;
937     else
938         startPosition = static_cast<unsigned>(dpos);
939
940     if (len < otherJSString->length())
941         return JSValue::encode(jsNumber(-1));
942
943     String thisString = thisJSString->value(exec);
944     String otherString = otherJSString->value(exec);
945     size_t result;
946     if (!startPosition)
947         result = thisString.startsWith(otherString) ? 0 : notFound;
948     else
949         result = thisString.reverseFind(otherString, startPosition);
950     if (result == notFound)
951         return JSValue::encode(jsNumber(-1));
952     return JSValue::encode(jsNumber(result));
953 }
954
955 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
956 {
957     JSValue thisValue = exec->thisValue();
958     if (!checkObjectCoercible(thisValue))
959         return throwVMTypeError(exec);
960     JSString* string = thisValue.toString(exec);
961     String s = string->value(exec);
962     VM* vm = &exec->vm();
963
964     JSValue a0 = exec->argument(0);
965
966     RegExp* regExp;
967     bool global = false;
968     if (a0.inherits(RegExpObject::info())) {
969         RegExpObject* regExpObject = asRegExpObject(a0);
970         regExp = regExpObject->regExp();
971         if ((global = regExp->global())) {
972             // ES5.1 15.5.4.10 step 8.a.
973             regExpObject->setLastIndex(exec, 0);
974             if (exec->hadException())
975                 return JSValue::encode(JSValue());
976         }
977     } else {
978         /*
979          *  ECMA 15.5.4.12 String.prototype.search (regexp)
980          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
981          *  replaced with the result of the expression new RegExp(regexp).
982          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
983          */
984         regExp = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
985         if (!regExp->isValid())
986             return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
987     }
988     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
989     MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
990     // case without 'g' flag is handled like RegExp.prototype.exec
991     if (!global)
992         return JSValue::encode(result ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull());
993
994     // return array of matches
995     MarkedArgumentBuffer list;
996     while (result) {
997         size_t end = result.end;
998         size_t length = end - result.start;
999         list.append(jsSubstring(exec, s, result.start, length));
1000         if (!length)
1001             ++end;
1002         result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
1003     }
1004     if (list.isEmpty()) {
1005         // if there are no matches at all, it's important to return
1006         // Null instead of an empty array, because this matches
1007         // other browsers and because Null is a false value.
1008         return JSValue::encode(jsNull());
1009     }
1010
1011     return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
1012 }
1013
1014 EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
1015 {
1016     JSValue thisValue = exec->thisValue();
1017     if (!checkObjectCoercible(thisValue))
1018         return throwVMTypeError(exec);
1019     JSString* string = thisValue.toString(exec);
1020     String s = string->value(exec);
1021     VM* vm = &exec->vm();
1022
1023     JSValue a0 = exec->argument(0);
1024
1025     RegExp* reg;
1026     if (a0.inherits(RegExpObject::info()))
1027         reg = asRegExpObject(a0)->regExp();
1028     else { 
1029         /*
1030          *  ECMA 15.5.4.12 String.prototype.search (regexp)
1031          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
1032          *  replaced with the result of the expression new RegExp(regexp).
1033          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
1034          */
1035         reg = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
1036         if (!reg->isValid())
1037             return throwVMError(exec, createSyntaxError(exec, reg->errorMessage()));
1038     }
1039     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
1040     MatchResult result = regExpConstructor->performMatch(*vm, reg, string, s, 0);
1041     return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
1042 }
1043
1044 EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
1045 {
1046     JSValue thisValue = exec->thisValue();
1047     if (!checkObjectCoercible(thisValue))
1048         return throwVMTypeError(exec);
1049     String s = thisValue.toString(exec)->value(exec);
1050     int len = s.length();
1051     RELEASE_ASSERT(len >= 0);
1052
1053     JSValue a0 = exec->argument(0);
1054     JSValue a1 = exec->argument(1);
1055
1056     // The arg processing is very much like ArrayProtoFunc::Slice
1057     double start = a0.toInteger(exec);
1058     double end = a1.isUndefined() ? len : a1.toInteger(exec);
1059     double from = start < 0 ? len + start : start;
1060     double to = end < 0 ? len + end : end;
1061     if (to > from && to > 0 && from < len) {
1062         if (from < 0)
1063             from = 0;
1064         if (to > len)
1065             to = len;
1066         return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
1067     }
1068
1069     return JSValue::encode(jsEmptyString(exec));
1070 }
1071
1072 // Return true in case of early return (resultLength got to limitLength).
1073 template<typename CharacterType>
1074 static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, JSValue originalValue, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
1075 {
1076     // 12. Let q = p.
1077     size_t matchPosition;
1078     const CharacterType* characters = string->characters<CharacterType>();
1079     // 13. Repeat, while q != s
1080     //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1081     //   b. If z is failure, then let q = q+1.
1082     //   c. Else, z is not failure
1083     while ((matchPosition = WTF::find(characters, string->length(), separatorCharacter, position)) != notFound) {
1084         // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1085         //    through q (exclusive).
1086         // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1087         //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1088         result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
1089         // 3. Increment lengthA by 1.
1090         // 4. If lengthA == lim, return A.
1091         if (++resultLength == limitLength)
1092             return true;
1093
1094         // 5. Let p = e.
1095         // 8. Let q = p.
1096         position = matchPosition + 1;
1097     }
1098     return false;
1099 }
1100
1101 // ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
1102 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
1103 {
1104     // 1. Call CheckObjectCoercible passing the this value as its argument.
1105     JSValue thisValue = exec->thisValue();
1106     if (!checkObjectCoercible(thisValue))
1107         return throwVMTypeError(exec);
1108
1109     // 2. Let S be the result of calling ToString, giving it the this value as its argument.
1110     // 6. Let s be the number of characters in S.
1111     String input = thisValue.toString(exec)->value(exec);
1112
1113     // 3. Let A be a new array created as if by the expression new Array()
1114     //    where Array is the standard built-in constructor with that name.
1115     JSArray* result = constructEmptyArray(exec, 0);
1116
1117     // 4. Let lengthA be 0.
1118     unsigned resultLength = 0;
1119
1120     // 5. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
1121     JSValue limitValue = exec->argument(1);
1122     unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
1123
1124     // 7. Let p = 0.
1125     size_t position = 0;
1126
1127     // 8. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
1128     //    otherwise let R = ToString(separator).
1129     JSValue separatorValue = exec->argument(0);
1130     if (separatorValue.inherits(RegExpObject::info())) {
1131         VM* vm = &exec->vm();
1132         RegExp* reg = asRegExpObject(separatorValue)->regExp();
1133
1134         // 9. If lim == 0, return A.
1135         if (!limit)
1136             return JSValue::encode(result);
1137
1138         // 10. If separator is undefined, then
1139         if (separatorValue.isUndefined()) {
1140             // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1141             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1142             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1143             // b. Return A.
1144             return JSValue::encode(result);
1145         }
1146
1147         // 11. If s == 0, then
1148         if (input.isEmpty()) {
1149             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1150             // b. If z is not failure, return A.
1151             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1152             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1153             // d. Return A.
1154             if (!reg->match(*vm, input, 0))
1155                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1156             return JSValue::encode(result);
1157         }
1158
1159         // 12. Let q = p.
1160         size_t matchPosition = 0;
1161         // 13. Repeat, while q != s
1162         while (matchPosition < input.length()) {
1163             // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1164             Vector<int, 32> ovector;
1165             int mpos = reg->match(*vm, input, matchPosition, ovector);
1166
1167             // b. If z is a failure then we can break because there are no matches
1168             if (mpos < 0)
1169                 break;
1170             matchPosition = mpos;
1171
1172             // if the match is the empty match at the end, break.
1173             if (matchPosition >= input.length())
1174                 break;
1175
1176             // c. Else, z is not failure
1177             // i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
1178             size_t matchEnd = ovector[1];
1179
1180             // ii. If e == p, then let q = q + 1.
1181             if (matchEnd == position) {
1182                 ++matchPosition;
1183                 continue;
1184             }
1185             // iii. if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
1186             ASSERT(matchEnd);
1187
1188             // iii. Else, e != p
1189
1190             // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1191             //    through q (exclusive).
1192             // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1193             //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1194             result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
1195
1196             // 3. Increment lengthA by 1.
1197             // 4. If lengthA == lim, return A.
1198             if (++resultLength == limit)
1199                 return JSValue::encode(result);
1200
1201             // 5. Let p = e.
1202             // 8. Let q = p.
1203             position = matchEnd;
1204             matchPosition = matchEnd;
1205
1206             // 6. Let i = 0.
1207             // 7. Repeat, while i is not equal to the number of elements in cap.
1208             //  a Let i = i + 1.
1209             for (unsigned i = 1; i <= reg->numSubpatterns(); ++i) {
1210                 // b Call the [[DefineOwnProperty]] internal method of A with arguments
1211                 //   ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
1212                 //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1213                 int sub = ovector[i * 2];
1214                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
1215                 // c Increment lengthA by 1.
1216                 // d If lengthA == lim, return A.
1217                 if (++resultLength == limit)
1218                     return JSValue::encode(result);
1219             }
1220         }
1221     } else {
1222         String separator = separatorValue.toString(exec)->value(exec);
1223
1224         // 9. If lim == 0, return A.
1225         if (!limit)
1226             return JSValue::encode(result);
1227
1228         // 10. If separator is undefined, then
1229         JSValue separatorValue = exec->argument(0);
1230         if (separatorValue.isUndefined()) {
1231             // a.  Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1232             //     Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1233             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1234             // b.  Return A.
1235             return JSValue::encode(result);
1236         }
1237
1238         // 11. If s == 0, then
1239         if (input.isEmpty()) {
1240             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1241             // b. If z is not failure, return A.
1242             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1243             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1244             // d. Return A.
1245             if (!separator.isEmpty())
1246                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1247             return JSValue::encode(result);
1248         }
1249
1250         // Optimized case for splitting on the empty string.
1251         if (separator.isEmpty()) {
1252             limit = std::min(limit, input.length());
1253             // Zero limt/input length handled in steps 9/11 respectively, above.
1254             ASSERT(limit);
1255
1256             do {
1257                 result->putDirectIndex(exec, position, jsSingleCharacterString(exec, input[position]));
1258             } while (++position < limit);
1259
1260             return JSValue::encode(result);
1261         }
1262
1263         // 3 cases:
1264         // -separator length == 1, 8 bits
1265         // -separator length == 1, 16 bits
1266         // -separator length > 1
1267         StringImpl* stringImpl = input.impl();
1268         StringImpl* separatorImpl = separator.impl();
1269         size_t separatorLength = separatorImpl->length();
1270
1271         if (separatorLength == 1) {
1272             UChar separatorCharacter;
1273             if (separatorImpl->is8Bit())
1274                 separatorCharacter = separatorImpl->characters8()[0];
1275             else
1276                 separatorCharacter = separatorImpl->characters16()[0];
1277
1278             if (stringImpl->is8Bit()) {
1279                 if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
1280                     return JSValue::encode(result);
1281             } else {
1282                 if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
1283                     return JSValue::encode(result);
1284             }
1285         } else {
1286             // 12. Let q = p.
1287             size_t matchPosition;
1288             // 13. Repeat, while q != s
1289             //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1290             //   b. If z is failure, then let q = q+1.
1291             //   c. Else, z is not failure
1292             while ((matchPosition = stringImpl->find(separatorImpl, position)) != notFound) {
1293                 // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1294                 //    through q (exclusive).
1295                 // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1296                 //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1297                 result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
1298                 // 3. Increment lengthA by 1.
1299                 // 4. If lengthA == lim, return A.
1300                 if (++resultLength == limit)
1301                     return JSValue::encode(result);
1302
1303                 // 5. Let p = e.
1304                 // 8. Let q = p.
1305                 position = matchPosition + separator.length();
1306             }
1307         }
1308     }
1309
1310     // 14. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1311     //     through s (exclusive).
1312     // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
1313     //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1314     result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
1315
1316     // 16. Return A.
1317     return JSValue::encode(result);
1318 }
1319
1320 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
1321 {
1322     JSValue thisValue = exec->thisValue();
1323     if (!checkObjectCoercible(thisValue))
1324         return throwVMTypeError(exec);
1325     unsigned len;
1326     JSString* jsString = 0;
1327     String uString;
1328     if (thisValue.isString()) {
1329         jsString = jsCast<JSString*>(thisValue.asCell());
1330         len = jsString->length();
1331     } else {
1332         uString = thisValue.toString(exec)->value(exec);
1333         if (exec->hadException())
1334             return JSValue::encode(jsUndefined());
1335         len = uString.length();
1336     }
1337
1338     JSValue a0 = exec->argument(0);
1339     JSValue a1 = exec->argument(1);
1340
1341     double start = a0.toInteger(exec);
1342     double length = a1.isUndefined() ? len : a1.toInteger(exec);
1343     if (start >= len || length <= 0)
1344         return JSValue::encode(jsEmptyString(exec));
1345     if (start < 0) {
1346         start += len;
1347         if (start < 0)
1348             start = 0;
1349     }
1350     if (start + length > len)
1351         length = len - start;
1352     unsigned substringStart = static_cast<unsigned>(start);
1353     unsigned substringLength = static_cast<unsigned>(length);
1354     if (jsString)
1355         return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1356     return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
1357 }
1358
1359 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
1360 {
1361     SamplingRegion samplingRegion("Doing substringing");
1362     JSValue thisValue = exec->thisValue();
1363     if (!checkObjectCoercible(thisValue))
1364         return throwVMTypeError(exec);
1365
1366     JSString* jsString = thisValue.toString(exec);
1367     if (exec->hadException())
1368         return JSValue::encode(jsUndefined());
1369
1370     JSValue a0 = exec->argument(0);
1371     JSValue a1 = exec->argument(1);
1372     int len = jsString->length();
1373     RELEASE_ASSERT(len >= 0);
1374
1375     double start = a0.toNumber(exec);
1376     double end;
1377     if (!(start >= 0)) // check for negative values or NaN
1378         start = 0;
1379     else if (start > len)
1380         start = len;
1381     if (a1.isUndefined())
1382         end = len;
1383     else { 
1384         end = a1.toNumber(exec);
1385         if (!(end >= 0)) // check for negative values or NaN
1386             end = 0;
1387         else if (end > len)
1388             end = len;
1389     }
1390     if (start > end) {
1391         double temp = end;
1392         end = start;
1393         start = temp;
1394     }
1395     unsigned substringStart = static_cast<unsigned>(start);
1396     unsigned substringLength = static_cast<unsigned>(end) - substringStart;
1397     return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1398 }
1399
1400 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
1401 {
1402     JSValue thisValue = exec->thisValue();
1403     if (!checkObjectCoercible(thisValue))
1404         return throwVMTypeError(exec);
1405     JSString* sVal = thisValue.toString(exec);
1406     const String& s = sVal->value(exec);
1407
1408     int sSize = s.length();
1409     if (!sSize)
1410         return JSValue::encode(sVal);
1411     RELEASE_ASSERT(sSize >= 0);
1412
1413     StringImpl* ourImpl = s.impl();
1414     RefPtr<StringImpl> lower = ourImpl->lower();
1415     if (ourImpl == lower)
1416         return JSValue::encode(sVal);
1417     return JSValue::encode(jsString(exec, String(lower.release())));
1418 }
1419
1420 EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
1421 {
1422     JSValue thisValue = exec->thisValue();
1423     if (!checkObjectCoercible(thisValue))
1424         return throwVMTypeError(exec);
1425     JSString* sVal = thisValue.toString(exec);
1426     const String& s = sVal->value(exec);
1427
1428     int sSize = s.length();
1429     if (!sSize)
1430         return JSValue::encode(sVal);
1431
1432     StringImpl* sImpl = s.impl();
1433     RefPtr<StringImpl> upper = sImpl->upper();
1434     if (sImpl == upper)
1435         return JSValue::encode(sVal);
1436     return JSValue::encode(jsString(exec, String(upper.release())));
1437 }
1438
1439 EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
1440 {
1441     JSValue thisValue = exec->thisValue();
1442     if (!checkObjectCoercible(thisValue))
1443         return throwVMTypeError(exec);
1444     String s = thisValue.toString(exec)->value(exec);
1445
1446     JSValue a0 = exec->argument(0);
1447     return JSValue::encode(jsNumber(Collator().collate(s, a0.toString(exec)->value(exec))));
1448 }
1449
1450 #if ENABLE(INTL)
1451 static EncodedJSValue toLocaleCase(ExecState* state, int32_t (*convertCase)(UChar*, int32_t, const UChar*, int32_t, const char*, UErrorCode*))
1452 {
1453     // 1. Let O be RequireObjectCoercible(this value).
1454     JSValue thisValue = state->thisValue();
1455     if (!checkObjectCoercible(thisValue))
1456         return throwVMTypeError(state);
1457
1458     // 2. Let S be ToString(O).
1459     JSString* sVal = thisValue.toString(state);
1460     const String& s = sVal->value(state);
1461
1462     // 3. ReturnIfAbrupt(S).
1463     if (state->hadException())
1464         return JSValue::encode(jsUndefined());
1465
1466     // Optimization for empty strings.
1467     if (s.isEmpty())
1468         return JSValue::encode(sVal);
1469
1470     // 4. Let requestedLocales be CanonicalizeLocaleList(locales).
1471     Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
1472
1473     // 5. ReturnIfAbrupt(requestedLocales).
1474     if (state->hadException())
1475         return JSValue::encode(jsUndefined());
1476
1477     // 6. Let len be the number of elements in requestedLocales.
1478     size_t len = requestedLocales.size();
1479
1480     // 7. If len > 0, then
1481     // a. Let requestedLocale be the first element of requestedLocales.
1482     // 8. Else
1483     // a. Let requestedLocale be DefaultLocale().
1484     String requestedLocale = len > 0 ? requestedLocales.first() : defaultLocale();
1485
1486     // 9. Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences (6.2.1) removed.
1487     String noExtensionsLocale = removeUnicodeLocaleExtension(requestedLocale);
1488
1489     // 10. Let availableLocales be a List with the language tags of the languages for which the Unicode character database contains language sensitive case mappings.
1490     // Note 1: As of Unicode 5.1, the availableLocales list contains the elements "az", "lt", and "tr".
1491     const HashSet<String> availableLocales({ ASCIILiteral("az"), ASCIILiteral("lt"), ASCIILiteral("tr") });
1492
1493     // 11. Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale).
1494     String locale = bestAvailableLocale(availableLocales, noExtensionsLocale);
1495
1496     // 12. If locale is undefined, let locale be "und".
1497     if (locale.isNull())
1498         locale = ASCIILiteral("und");
1499
1500     CString utf8LocaleBuffer = locale.utf8();
1501     const StringView view(s);
1502     const int32_t viewLength = view.length();
1503
1504     // Delegate the following steps to icu u_strToLower or u_strToUpper.
1505     // 13. Let cpList be a List containing in order the code points of S as defined in ES2015, 6.1.4, starting at the first element of S.
1506     // 14. For each code point c in cpList, if the Unicode Character Database provides a lower(/upper) case equivalent of c that is either language insensitive or for the language locale, then replace c in cpList with that/those equivalent code point(s).
1507     // 15. Let cuList be a new List.
1508     // 16. For each code point c in cpList, in order, append to cuList the elements of the UTF-16 Encoding (defined in ES2015, 6.1.4) of c.
1509     // 17. Let L be a String whose elements are, in order, the elements of cuList.
1510
1511     // Most strings lower/upper case will be the same size as original, so try that first.
1512     UErrorCode error(U_ZERO_ERROR);
1513     Vector<UChar> buffer(viewLength);
1514     String lower;
1515     const int32_t resultLength = convertCase(buffer.data(), viewLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
1516     if (U_SUCCESS(error))
1517         lower = String(buffer.data(), resultLength);
1518     else if (error == U_BUFFER_OVERFLOW_ERROR) {
1519         // Converted case needs more space than original. Try again.
1520         UErrorCode error(U_ZERO_ERROR);
1521         Vector<UChar> buffer(resultLength);
1522         convertCase(buffer.data(), resultLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
1523         if (U_FAILURE(error))
1524             return throwVMTypeError(state, u_errorName(error));
1525         lower = String(buffer.data(), resultLength);
1526     } else
1527         return throwVMTypeError(state, u_errorName(error));
1528
1529     // 18. Return L.
1530     return JSValue::encode(jsString(state, lower));
1531 }
1532
1533 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleLowerCase(ExecState* state)
1534 {
1535     // 13.1.2 String.prototype.toLocaleLowerCase ([locales])
1536     // http://ecma-international.org/publications/standards/Ecma-402.htm
1537     return toLocaleCase(state, u_strToLower);
1538 }
1539
1540 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleUpperCase(ExecState* state)
1541 {
1542     // 13.1.3 String.prototype.toLocaleUpperCase ([locales])
1543     // http://ecma-international.org/publications/standards/Ecma-402.htm
1544     // This function interprets a string value as a sequence of code points, as described in ES2015, 6.1.4. This function behaves in exactly the same way as String.prototype.toLocaleLowerCase, except that characters are mapped to their uppercase equivalents as specified in the Unicode character database.
1545     return toLocaleCase(state, u_strToUpper);
1546 }
1547 #endif // ENABLE(INTL)
1548
1549 EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
1550 {
1551     JSValue thisValue = exec->thisValue();
1552     if (!checkObjectCoercible(thisValue))
1553         return throwVMTypeError(exec);
1554     String s = thisValue.toString(exec)->value(exec);
1555     return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
1556 }
1557
1558 EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
1559 {
1560     JSValue thisValue = exec->thisValue();
1561     if (!checkObjectCoercible(thisValue))
1562         return throwVMTypeError(exec);
1563     String s = thisValue.toString(exec)->value(exec);
1564     return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
1565 }
1566
1567 EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
1568 {
1569     JSValue thisValue = exec->thisValue();
1570     if (!checkObjectCoercible(thisValue))
1571         return throwVMTypeError(exec);
1572     String s = thisValue.toString(exec)->value(exec);
1573     return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
1574 }
1575
1576 EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
1577 {
1578     JSValue thisValue = exec->thisValue();
1579     if (!checkObjectCoercible(thisValue))
1580         return throwVMTypeError(exec);
1581     String s = thisValue.toString(exec)->value(exec);
1582     return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
1583 }
1584
1585 EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
1586 {
1587     JSValue thisValue = exec->thisValue();
1588     if (!checkObjectCoercible(thisValue))
1589         return throwVMTypeError(exec);
1590     String s = thisValue.toString(exec)->value(exec);
1591     return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
1592 }
1593
1594 EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
1595 {
1596     JSValue thisValue = exec->thisValue();
1597     if (!checkObjectCoercible(thisValue))
1598         return throwVMTypeError(exec);
1599     String s = thisValue.toString(exec)->value(exec);
1600     return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
1601 }
1602
1603 EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
1604 {
1605     JSValue thisValue = exec->thisValue();
1606     if (!checkObjectCoercible(thisValue))
1607         return throwVMTypeError(exec);
1608     String s = thisValue.toString(exec)->value(exec);
1609     return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
1610 }
1611
1612 EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
1613 {
1614     JSValue thisValue = exec->thisValue();
1615     if (!checkObjectCoercible(thisValue))
1616         return throwVMTypeError(exec);
1617     String s = thisValue.toString(exec)->value(exec);
1618     return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
1619 }
1620
1621 EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
1622 {
1623     JSValue thisValue = exec->thisValue();
1624     if (!checkObjectCoercible(thisValue))
1625         return throwVMTypeError(exec);
1626     String s = thisValue.toString(exec)->value(exec);
1627     return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
1628 }
1629
1630 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
1631 {
1632     JSValue thisValue = exec->thisValue();
1633     if (!checkObjectCoercible(thisValue))
1634         return throwVMTypeError(exec);
1635     String s = thisValue.toString(exec)->value(exec);
1636     JSValue a0 = exec->argument(0);
1637     String color = a0.toWTFString(exec);
1638     color.replaceWithLiteral('"', "&quot;");
1639
1640     return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>"));
1641 }
1642
1643 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
1644 {
1645     JSValue thisValue = exec->thisValue();
1646     if (!checkObjectCoercible(thisValue))
1647         return throwVMTypeError(exec);
1648     String s = thisValue.toString(exec)->value(exec);
1649     JSValue a0 = exec->argument(0);
1650
1651     uint32_t smallInteger;
1652     if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
1653         unsigned stringSize = s.length();
1654         unsigned bufferSize = 22 + stringSize;
1655         // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
1656         UChar* buffer;
1657         PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1658         if (!impl)
1659             return JSValue::encode(jsUndefined());
1660         buffer[0] = '<';
1661         buffer[1] = 'f';
1662         buffer[2] = 'o';
1663         buffer[3] = 'n';
1664         buffer[4] = 't';
1665         buffer[5] = ' ';
1666         buffer[6] = 's';
1667         buffer[7] = 'i';
1668         buffer[8] = 'z';
1669         buffer[9] = 'e';
1670         buffer[10] = '=';
1671         buffer[11] = '"';
1672         buffer[12] = '0' + smallInteger;
1673         buffer[13] = '"';
1674         buffer[14] = '>';
1675         StringView(s).getCharactersWithUpconvert(&buffer[15]);
1676         buffer[15 + stringSize] = '<';
1677         buffer[16 + stringSize] = '/';
1678         buffer[17 + stringSize] = 'f';
1679         buffer[18 + stringSize] = 'o';
1680         buffer[19 + stringSize] = 'n';
1681         buffer[20 + stringSize] = 't';
1682         buffer[21 + stringSize] = '>';
1683         return JSValue::encode(jsNontrivialString(exec, impl));
1684     }
1685
1686     String fontSize = a0.toWTFString(exec);
1687     fontSize.replaceWithLiteral('"', "&quot;");
1688
1689     return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>"));
1690 }
1691
1692 EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
1693 {
1694     JSValue thisValue = exec->thisValue();
1695     if (!checkObjectCoercible(thisValue))
1696         return throwVMTypeError(exec);
1697     String s = thisValue.toString(exec)->value(exec);
1698     JSValue a0 = exec->argument(0);
1699     String anchor = a0.toWTFString(exec);
1700     anchor.replaceWithLiteral('"', "&quot;");
1701
1702     return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>"));
1703 }
1704
1705 EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
1706 {
1707     JSValue thisValue = exec->thisValue();
1708     if (!checkObjectCoercible(thisValue))
1709         return throwVMTypeError(exec);
1710     String s = thisValue.toString(exec)->value(exec);
1711     JSValue a0 = exec->argument(0);
1712     String linkText = a0.toWTFString(exec);
1713     linkText.replaceWithLiteral('"', "&quot;");
1714
1715     unsigned linkTextSize = linkText.length();
1716     unsigned stringSize = s.length();
1717     unsigned bufferSize = 15 + linkTextSize + stringSize;
1718     // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
1719     UChar* buffer;
1720     PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1721     if (!impl)
1722         return JSValue::encode(jsUndefined());
1723     buffer[0] = '<';
1724     buffer[1] = 'a';
1725     buffer[2] = ' ';
1726     buffer[3] = 'h';
1727     buffer[4] = 'r';
1728     buffer[5] = 'e';
1729     buffer[6] = 'f';
1730     buffer[7] = '=';
1731     buffer[8] = '"';
1732     StringView(linkText).getCharactersWithUpconvert(&buffer[9]);
1733     buffer[9 + linkTextSize] = '"';
1734     buffer[10 + linkTextSize] = '>';
1735     StringView(s).getCharactersWithUpconvert(&buffer[11 + linkTextSize]);
1736     buffer[11 + linkTextSize + stringSize] = '<';
1737     buffer[12 + linkTextSize + stringSize] = '/';
1738     buffer[13 + linkTextSize + stringSize] = 'a';
1739     buffer[14 + linkTextSize + stringSize] = '>';
1740     return JSValue::encode(jsNontrivialString(exec, impl));
1741 }
1742
1743 enum {
1744     TrimLeft = 1,
1745     TrimRight = 2
1746 };
1747
1748 static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
1749 {
1750     if (!checkObjectCoercible(thisValue))
1751         return throwTypeError(exec);
1752     String str = thisValue.toString(exec)->value(exec);
1753     unsigned left = 0;
1754     if (trimKind & TrimLeft) {
1755         while (left < str.length() && isStrWhiteSpace(str[left]))
1756             left++;
1757     }
1758     unsigned right = str.length();
1759     if (trimKind & TrimRight) {
1760         while (right > left && isStrWhiteSpace(str[right - 1]))
1761             right--;
1762     }
1763
1764     // Don't gc allocate a new string if we don't have to.
1765     if (left == 0 && right == str.length() && thisValue.isString())
1766         return thisValue;
1767
1768     return jsString(exec, str.substringSharingImpl(left, right - left));
1769 }
1770
1771 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
1772 {
1773     JSValue thisValue = exec->thisValue();
1774     return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
1775 }
1776
1777 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
1778 {
1779     JSValue thisValue = exec->thisValue();
1780     return JSValue::encode(trimString(exec, thisValue, TrimLeft));
1781 }
1782
1783 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
1784 {
1785     JSValue thisValue = exec->thisValue();
1786     return JSValue::encode(trimString(exec, thisValue, TrimRight));
1787 }
1788
1789 static inline unsigned clampAndTruncateToUnsigned(double value, unsigned min, unsigned max)
1790 {
1791     if (value < min)
1792         return min;
1793     if (value > max)
1794         return max;
1795     return static_cast<unsigned>(value);
1796 }
1797
1798 EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
1799 {
1800     JSValue thisValue = exec->thisValue();
1801     if (!checkObjectCoercible(thisValue))
1802         return throwVMTypeError(exec);
1803
1804     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1805     if (exec->hadException())
1806         return JSValue::encode(jsUndefined());
1807
1808     JSValue a0 = exec->argument(0);
1809     if (jsDynamicCast<RegExpObject*>(a0))
1810         return throwVMTypeError(exec);
1811
1812     String searchString = a0.toString(exec)->value(exec);
1813     if (exec->hadException())
1814         return JSValue::encode(jsUndefined());
1815
1816     JSValue positionArg = exec->argument(1);
1817     unsigned start = 0;
1818     if (positionArg.isInt32())
1819         start = std::max(0, positionArg.asInt32());
1820     else {
1821         unsigned length = stringToSearchIn.length();
1822         start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
1823         if (exec->hadException())
1824             return JSValue::encode(jsUndefined());
1825     }
1826
1827     return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixStartingAt(searchString, start)));
1828 }
1829
1830 EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec)
1831 {
1832     JSValue thisValue = exec->thisValue();
1833     if (!checkObjectCoercible(thisValue))
1834         return throwVMTypeError(exec);
1835
1836     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1837     if (exec->hadException())
1838         return JSValue::encode(jsUndefined());
1839
1840     JSValue a0 = exec->argument(0);
1841     if (jsDynamicCast<RegExpObject*>(a0))
1842         return throwVMTypeError(exec);
1843
1844     String searchString = a0.toString(exec)->value(exec);
1845     if (exec->hadException())
1846         return JSValue::encode(jsUndefined());
1847
1848     unsigned length = stringToSearchIn.length();
1849
1850     JSValue endPositionArg = exec->argument(1);
1851     unsigned end = length;
1852     if (endPositionArg.isInt32())
1853         end = std::max(0, endPositionArg.asInt32());
1854     else if (!endPositionArg.isUndefined()) {
1855         end = clampAndTruncateToUnsigned(endPositionArg.toInteger(exec), 0, length);
1856         if (exec->hadException())
1857             return JSValue::encode(jsUndefined());
1858     }
1859
1860     return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, std::min(end, length))));
1861 }
1862
1863 EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
1864 {
1865     JSValue thisValue = exec->thisValue();
1866     if (!checkObjectCoercible(thisValue))
1867         return throwVMTypeError(exec);
1868
1869     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1870     if (exec->hadException())
1871         return JSValue::encode(jsUndefined());
1872
1873     JSValue a0 = exec->argument(0);
1874     if (jsDynamicCast<RegExpObject*>(a0))
1875         return throwVMTypeError(exec);
1876
1877     String searchString = a0.toString(exec)->value(exec);
1878     if (exec->hadException())
1879         return JSValue::encode(jsUndefined());
1880
1881     JSValue positionArg = exec->argument(1);
1882     unsigned start = 0;
1883     if (positionArg.isInt32())
1884         start = std::max(0, positionArg.asInt32());
1885     else {
1886         unsigned length = stringToSearchIn.length();
1887         start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
1888         if (exec->hadException())
1889             return JSValue::encode(jsUndefined());
1890     }
1891
1892     return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
1893 }
1894
1895 EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState* exec)
1896 {
1897     JSValue thisValue = exec->thisValue();
1898     if (!checkObjectCoercible(thisValue))
1899         return throwVMTypeError(exec);
1900     JSString* string = thisValue.toString(exec);
1901     return JSValue::encode(JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), string));
1902 }
1903
1904 static JSValue normalize(ExecState* exec, const UChar* source, size_t sourceLength, UNormalizationMode form)
1905 {
1906     UErrorCode status = U_ZERO_ERROR;
1907     int32_t normalizedStringLength = unorm_normalize(source, sourceLength, form, 0, nullptr, 0, &status);
1908
1909     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
1910         // The behavior is not specified when normalize fails.
1911         // Now we throw a type erorr since it seems that the contents of the string are invalid.
1912         return throwTypeError(exec);
1913     }
1914
1915     UChar* buffer = nullptr;
1916     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(normalizedStringLength, buffer);
1917     if (!impl)
1918         return throwOutOfMemoryError(exec);
1919
1920     status = U_ZERO_ERROR;
1921     unorm_normalize(source, sourceLength, form, 0, buffer, normalizedStringLength, &status);
1922     if (U_FAILURE(status))
1923         return throwTypeError(exec);
1924
1925     return jsString(exec, impl.get());
1926 }
1927
1928 EncodedJSValue JSC_HOST_CALL stringProtoFuncNormalize(ExecState* exec)
1929 {
1930     JSValue thisValue = exec->thisValue();
1931     if (!checkObjectCoercible(thisValue))
1932         return throwVMTypeError(exec);
1933     JSString::SafeView source = thisValue.toString(exec)->view(exec);
1934     if (exec->hadException())
1935         return JSValue::encode(jsUndefined());
1936
1937     UNormalizationMode form = UNORM_NFC;
1938     // Verify that the argument is provided and is not undefined.
1939     if (!exec->argument(0).isUndefined()) {
1940         String formString = exec->uncheckedArgument(0).toString(exec)->value(exec);
1941         if (exec->hadException())
1942             return JSValue::encode(jsUndefined());
1943
1944         if (formString == "NFC")
1945             form = UNORM_NFC;
1946         else if (formString == "NFD")
1947             form = UNORM_NFD;
1948         else if (formString == "NFKC")
1949             form = UNORM_NFKC;
1950         else if (formString == "NFKD")
1951             form = UNORM_NFKD;
1952         else
1953             return throwVMError(exec, createRangeError(exec, ASCIILiteral("argument does not match any normalization form")));
1954     }
1955
1956     return JSValue::encode(normalize(exec, source.get().upconvertedCharacters(), source.length(), form));
1957 }
1958
1959 } // namespace JSC