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