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