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