Turn String.prototype.replace into an intrinsic
[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 NEVER_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     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
510
511     size_t lastIndex = 0;
512     unsigned startPosition = 0;
513
514     Vector<StringRange, 16> sourceRanges;
515     Vector<String, 16> replacements;
516
517     // This is either a loop (if global is set) or a one-way (if not).
518     if (global && callType == CallTypeJS) {
519         // regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
520         int argCount = regExp->numSubpatterns() + 1 + 2;
521         JSFunction* func = jsCast<JSFunction*>(replaceValue);
522         CachedCall cachedCall(exec, func, argCount);
523         if (exec->hadException())
524             return JSValue::encode(jsUndefined());
525         VM* vm = &exec->vm();
526         if (source.is8Bit()) {
527             while (true) {
528                 int* ovector;
529                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
530                 if (!result)
531                     break;
532
533                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
534
535                 unsigned i = 0;
536                 for (; i < regExp->numSubpatterns() + 1; ++i) {
537                     int matchStart = ovector[i * 2];
538                     int matchLen = ovector[i * 2 + 1] - matchStart;
539
540                     if (matchStart < 0)
541                         cachedCall.setArgument(i, jsUndefined());
542                     else
543                         cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen));
544                 }
545
546                 cachedCall.setArgument(i++, jsNumber(result.start));
547                 cachedCall.setArgument(i++, string);
548
549                 cachedCall.setThis(jsUndefined());
550                 JSValue jsResult = cachedCall.call();
551                 replacements.append(jsResult.toString(exec)->value(exec));
552                 if (exec->hadException())
553                     return JSValue::encode(jsUndefined());
554
555                 lastIndex = result.end;
556                 startPosition = lastIndex;
557
558                 // special case of empty match
559                 if (result.empty()) {
560                     startPosition++;
561                     if (startPosition > sourceLen)
562                         break;
563                 }
564             }
565         } else {
566             while (true) {
567                 int* ovector;
568                 MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
569                 if (!result)
570                     break;
571
572                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
573
574                 unsigned i = 0;
575                 for (; i < regExp->numSubpatterns() + 1; ++i) {
576                     int matchStart = ovector[i * 2];
577                     int matchLen = ovector[i * 2 + 1] - matchStart;
578
579                     if (matchStart < 0)
580                         cachedCall.setArgument(i, jsUndefined());
581                     else
582                         cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen));
583                 }
584
585                 cachedCall.setArgument(i++, jsNumber(result.start));
586                 cachedCall.setArgument(i++, string);
587
588                 cachedCall.setThis(jsUndefined());
589                 JSValue jsResult = cachedCall.call();
590                 replacements.append(jsResult.toString(exec)->value(exec));
591                 if (exec->hadException())
592                     return JSValue::encode(jsUndefined());
593
594                 lastIndex = result.end;
595                 startPosition = lastIndex;
596
597                 // special case of empty match
598                 if (result.empty()) {
599                     startPosition++;
600                     if (startPosition > sourceLen)
601                         break;
602                 }
603             }
604         }
605     } else {
606         VM* vm = &exec->vm();
607         do {
608             int* ovector;
609             MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, source, startPosition, &ovector);
610             if (!result)
611                 break;
612
613             if (callType != CallTypeNone) {
614                 sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
615
616                 MarkedArgumentBuffer args;
617
618                 for (unsigned i = 0; i < regExp->numSubpatterns() + 1; ++i) {
619                     int matchStart = ovector[i * 2];
620                     int matchLen = ovector[i * 2 + 1] - matchStart;
621
622                     if (matchStart < 0)
623                         args.append(jsUndefined());
624                     else
625                         args.append(jsSubstring(exec, source, matchStart, matchLen));
626                 }
627
628                 args.append(jsNumber(result.start));
629                 args.append(string);
630
631                 replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec));
632                 if (exec->hadException())
633                     return JSValue::encode(jsUndefined());
634             } else {
635                 int replLen = replacementString.length();
636                 if (lastIndex < result.start || replLen) {
637                     sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
638
639                     if (replLen)
640                         replacements.append(substituteBackreferences(replacementString, source, ovector, regExp));
641                     else
642                         replacements.append(String());
643                 }
644             }
645
646             lastIndex = result.end;
647             startPosition = lastIndex;
648
649             // special case of empty match
650             if (result.empty()) {
651                 startPosition++;
652                 if (startPosition > sourceLen)
653                     break;
654             }
655         } while (global);
656     }
657
658     if (!lastIndex && replacements.isEmpty())
659         return JSValue::encode(string);
660
661     if (static_cast<unsigned>(lastIndex) < sourceLen)
662         sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
663
664     return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
665 }
666
667 EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
668     ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceString)
669 {
670     CallData callData;
671     String replacementString = replaceString->value(exec);
672     return replaceUsingRegExpSearch(
673         exec, thisValue, searchValue, callData, CallTypeNone, replacementString, replaceString);
674 }
675
676 static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
677 {
678     String replacementString;
679     CallData callData;
680     CallType callType = getCallData(replaceValue, callData);
681     if (callType == CallTypeNone) {
682         replacementString = replaceValue.toString(exec)->value(exec);
683         if (exec->hadException())
684             return JSValue::encode(jsUndefined());
685     }
686
687     return replaceUsingRegExpSearch(
688         exec, string, searchValue, callData, callType, replacementString, replaceValue);
689 }
690
691 static ALWAYS_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
692 {
693     const String& string = jsString->value(exec);
694     String searchString = searchValue.toString(exec)->value(exec);
695     if (exec->hadException())
696         return JSValue::encode(jsUndefined());
697
698     size_t matchStart = string.find(searchString);
699
700     if (matchStart == notFound)
701         return JSValue::encode(jsString);
702
703     CallData callData;
704     CallType callType = getCallData(replaceValue, callData);
705     if (callType != CallTypeNone) {
706         MarkedArgumentBuffer args;
707         args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
708         args.append(jsNumber(matchStart));
709         args.append(jsString);
710         replaceValue = call(exec, replaceValue, callType, callData, jsUndefined(), args);
711         if (exec->hadException())
712             return JSValue::encode(jsUndefined());
713     }
714
715     String replaceString = replaceValue.toString(exec)->value(exec);
716     if (exec->hadException())
717         return JSValue::encode(jsUndefined());
718
719     StringImpl* stringImpl = string.impl();
720     String leftPart(StringImpl::createSubstringSharingImpl(stringImpl, 0, matchStart));
721
722     size_t matchEnd = matchStart + searchString.impl()->length();
723     int ovector[2] = { static_cast<int>(matchStart),  static_cast<int>(matchEnd)};
724     String middlePart = substituteBackreferences(replaceString, string, ovector, 0);
725
726     size_t leftLength = stringImpl->length() - matchEnd;
727     String rightPart(StringImpl::createSubstringSharingImpl(stringImpl, matchEnd, leftLength));
728     return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart));
729 }
730
731 static inline bool checkObjectCoercible(JSValue thisValue)
732 {
733     if (thisValue.isString())
734         return true;
735
736     if (thisValue.isUndefinedOrNull())
737         return false;
738
739     if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isEnvironmentRecord())
740         return false;
741
742     return true;
743 }
744
745 template <typename CharacterType>
746 static inline JSValue repeatCharacter(ExecState* exec, CharacterType character, unsigned repeatCount)
747 {
748     CharacterType* buffer = nullptr;
749     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(repeatCount, buffer);
750     if (!impl)
751         return throwOutOfMemoryError(exec);
752
753     std::fill_n(buffer, repeatCount, character);
754
755     return jsString(exec, impl.release());
756 }
757
758 EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec)
759 {
760     JSValue thisValue = exec->thisValue();
761     if (!checkObjectCoercible(thisValue))
762         return throwVMTypeError(exec);
763
764     JSString* string = thisValue.toString(exec);
765     if (exec->hadException())
766         return JSValue::encode(jsUndefined());
767
768     double repeatCountDouble = exec->argument(0).toInteger(exec);
769     if (exec->hadException())
770         return JSValue::encode(jsUndefined());
771     if (repeatCountDouble < 0 || std::isinf(repeatCountDouble))
772         return throwVMError(exec, createRangeError(exec, ASCIILiteral("repeat() argument must be greater than or equal to 0 and not be infinity")));
773
774     VM& vm = exec->vm();
775
776     if (!string->length() || !repeatCountDouble)
777         return JSValue::encode(jsEmptyString(&vm));
778
779     if (repeatCountDouble == 1)
780         return JSValue::encode(string);
781
782     // JSString requires the limitation that its length is in the range of int32_t.
783     if (repeatCountDouble > std::numeric_limits<int32_t>::max() / string->length())
784         return JSValue::encode(throwOutOfMemoryError(exec));
785     unsigned repeatCount = static_cast<unsigned>(repeatCountDouble);
786
787     // For a string which length is small, instead of creating ropes,
788     // allocating a sequential buffer and fill with the repeated string for efficiency.
789     if (string->length() == 1) {
790         String repeatedString = string->value(exec);
791         UChar character = repeatedString.at(0);
792         if (!(character & ~0xff))
793             return JSValue::encode(repeatCharacter(exec, static_cast<LChar>(character), repeatCount));
794         return JSValue::encode(repeatCharacter(exec, character, repeatCount));
795     }
796
797     JSRopeString::RopeBuilder ropeBuilder(vm);
798     for (unsigned i = 0; i < repeatCount; ++i) {
799         if (!ropeBuilder.append(string))
800             return JSValue::encode(throwOutOfMemoryError(exec));
801     }
802     return JSValue::encode(ropeBuilder.release());
803 }
804
805 ALWAYS_INLINE EncodedJSValue replace(
806     ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
807 {
808     if (searchValue.inherits(RegExpObject::info()))
809         return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
810     return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
811 }
812
813 ALWAYS_INLINE EncodedJSValue replace(
814     ExecState* exec, JSValue thisValue, JSValue searchValue, JSValue replaceValue)
815 {
816     if (!checkObjectCoercible(thisValue))
817         return throwVMTypeError(exec);
818     JSString* string = thisValue.toString(exec);
819     if (exec->hadException())
820         return JSValue::encode(jsUndefined());
821     return replace(exec, string, searchValue, replaceValue);
822 }
823
824 EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
825 {
826     return replace(exec, exec->thisValue(), exec->argument(0), exec->argument(1));
827 }
828
829 EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
830     ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
831     EncodedJSValue replaceValue)
832 {
833     return replace(
834         exec, JSValue::decode(thisValue), JSValue::decode(searchValue),
835         JSValue::decode(replaceValue));
836 }
837
838 EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
839 {
840     JSValue thisValue = exec->thisValue();
841     // Also used for valueOf.
842
843     if (thisValue.isString())
844         return JSValue::encode(thisValue);
845
846     if (thisValue.inherits(StringObject::info()))
847         return JSValue::encode(asStringObject(thisValue)->internalValue());
848
849     return throwVMTypeError(exec);
850 }
851
852 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
853 {
854     JSValue thisValue = exec->thisValue();
855     if (!checkObjectCoercible(thisValue))
856         return throwVMTypeError(exec);
857     JSString::SafeView string = thisValue.toString(exec)->view(exec);
858     JSValue a0 = exec->argument(0);
859     if (a0.isUInt32()) {
860         uint32_t i = a0.asUInt32();
861         if (i < string.length())
862             return JSValue::encode(jsSingleCharacterString(exec, string[i]));
863         return JSValue::encode(jsEmptyString(exec));
864     }
865     double dpos = a0.toInteger(exec);
866     if (dpos >= 0 && dpos < string.length())
867         return JSValue::encode(jsSingleCharacterString(exec, string[static_cast<unsigned>(dpos)]));
868     return JSValue::encode(jsEmptyString(exec));
869 }
870
871 EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
872 {
873     JSValue thisValue = exec->thisValue();
874     if (!checkObjectCoercible(thisValue))
875         return throwVMTypeError(exec);
876     JSString::SafeView string = thisValue.toString(exec)->view(exec);
877     JSValue a0 = exec->argument(0);
878     if (a0.isUInt32()) {
879         uint32_t i = a0.asUInt32();
880         if (i < string.length())
881             return JSValue::encode(jsNumber(string[i]));
882         return JSValue::encode(jsNaN());
883     }
884     double dpos = a0.toInteger(exec);
885     if (dpos >= 0 && dpos < string.length())
886         return JSValue::encode(jsNumber(string[static_cast<int>(dpos)]));
887     return JSValue::encode(jsNaN());
888 }
889
890 static inline UChar32 codePointAt(const String& string, unsigned position, unsigned length)
891 {
892     RELEASE_ASSERT(position < length);
893     if (string.is8Bit())
894         return string.characters8()[position];
895     UChar32 character;
896     U16_NEXT(string.characters16(), position, length, character);
897     return character;
898 }
899
900 EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec)
901 {
902     JSValue thisValue = exec->thisValue();
903     if (!checkObjectCoercible(thisValue))
904         return throwVMTypeError(exec);
905
906     String string = thisValue.toWTFString(exec);
907     unsigned length = string.length();
908
909     JSValue argument0 = exec->argument(0);
910     if (argument0.isUInt32()) {
911         unsigned position = argument0.asUInt32();
912         if (position < length)
913             return JSValue::encode(jsNumber(codePointAt(string, position, length)));
914         return JSValue::encode(jsUndefined());
915     }
916
917     if (UNLIKELY(exec->hadException()))
918         return JSValue::encode(jsUndefined());
919
920     double doublePosition = argument0.toInteger(exec);
921     if (doublePosition >= 0 && doublePosition < length)
922         return JSValue::encode(jsNumber(codePointAt(string, static_cast<unsigned>(doublePosition), length)));
923     return JSValue::encode(jsUndefined());
924 }
925
926 EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
927 {
928     JSValue thisValue = exec->thisValue();
929     if (thisValue.isString() && exec->argumentCount() == 1)
930         return JSValue::encode(jsString(exec, asString(thisValue), exec->uncheckedArgument(0).toString(exec)));
931
932     if (!checkObjectCoercible(thisValue))
933         return throwVMTypeError(exec);
934     return JSValue::encode(jsStringFromArguments(exec, thisValue));
935 }
936
937 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
938 {
939     JSValue thisValue = exec->thisValue();
940     if (!checkObjectCoercible(thisValue))
941         return throwVMTypeError(exec);
942
943     JSValue a0 = exec->argument(0);
944     JSValue a1 = exec->argument(1);
945
946     JSString* thisJSString = thisValue.toString(exec);
947     JSString* otherJSString = a0.toString(exec);
948
949     unsigned pos = 0;
950     if (!a1.isUndefined()) {
951         int len = thisJSString->length();
952         RELEASE_ASSERT(len >= 0);
953         if (a1.isUInt32())
954             pos = std::min<uint32_t>(a1.asUInt32(), len);
955         else {
956             double dpos = a1.toInteger(exec);
957             if (dpos < 0)
958                 dpos = 0;
959             else if (dpos > len)
960                 dpos = len;
961             pos = static_cast<unsigned>(dpos);
962         }
963     }
964
965     if (thisJSString->length() < otherJSString->length() + pos)
966         return JSValue::encode(jsNumber(-1));
967
968     size_t result = thisJSString->view(exec).get().find(otherJSString->view(exec).get(), pos);
969     if (result == notFound)
970         return JSValue::encode(jsNumber(-1));
971     return JSValue::encode(jsNumber(result));
972 }
973
974 EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
975 {
976     JSValue thisValue = exec->thisValue();
977     if (!checkObjectCoercible(thisValue))
978         return throwVMTypeError(exec);
979
980     JSValue a0 = exec->argument(0);
981     JSValue a1 = exec->argument(1);
982
983     JSString* thisJSString = thisValue.toString(exec);
984     unsigned len = thisJSString->length();
985     JSString* otherJSString = a0.toString(exec);
986
987     double dpos = a1.toIntegerPreserveNaN(exec);
988     unsigned startPosition;
989     if (dpos < 0)
990         startPosition = 0;
991     else if (!(dpos <= len)) // true for NaN
992         startPosition = len;
993     else
994         startPosition = static_cast<unsigned>(dpos);
995
996     if (len < otherJSString->length())
997         return JSValue::encode(jsNumber(-1));
998
999     String thisString = thisJSString->value(exec);
1000     String otherString = otherJSString->value(exec);
1001     size_t result;
1002     if (!startPosition)
1003         result = thisString.startsWith(otherString) ? 0 : notFound;
1004     else
1005         result = thisString.reverseFind(otherString, startPosition);
1006     if (result == notFound)
1007         return JSValue::encode(jsNumber(-1));
1008     return JSValue::encode(jsNumber(result));
1009 }
1010
1011 EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
1012 {
1013     JSValue thisValue = exec->thisValue();
1014     if (!checkObjectCoercible(thisValue))
1015         return throwVMTypeError(exec);
1016     JSString* string = thisValue.toString(exec);
1017     String s = string->value(exec);
1018     VM* vm = &exec->vm();
1019
1020     JSValue a0 = exec->argument(0);
1021
1022     RegExp* regExp;
1023     bool global = false;
1024     if (a0.inherits(RegExpObject::info())) {
1025         RegExpObject* regExpObject = asRegExpObject(a0);
1026         regExp = regExpObject->regExp();
1027         if ((global = regExp->global())) {
1028             // ES5.1 15.5.4.10 step 8.a.
1029             regExpObject->setLastIndex(exec, 0);
1030             if (exec->hadException())
1031                 return JSValue::encode(jsUndefined());
1032         }
1033     } else {
1034         /*
1035          *  ECMA 15.5.4.12 String.prototype.search (regexp)
1036          *  If regexp is not an object whose [[Class]] property is "RegExp", it is
1037          *  replaced with the result of the expression new RegExp(regexp).
1038          *  Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
1039          */
1040         String patternString = emptyString();
1041         if (!a0.isUndefined()) {
1042             patternString = a0.toString(exec)->value(exec);
1043             if (exec->hadException())
1044                 return JSValue::encode(jsUndefined());
1045         }
1046         regExp = RegExp::create(exec->vm(), patternString, NoFlags);
1047         if (!regExp->isValid())
1048             return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
1049     }
1050     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
1051     MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
1052     // case without 'g' flag is handled like RegExp.prototype.exec
1053     if (!global)
1054         return JSValue::encode(result ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull());
1055
1056     // return array of matches
1057     MarkedArgumentBuffer list;
1058     while (result) {
1059         // We defend ourselves from crazy.
1060         const size_t maximumReasonableMatchSize = 1000000000;
1061         if (list.size() > maximumReasonableMatchSize) {
1062             throwOutOfMemoryError(exec);
1063             return JSValue::encode(jsUndefined());
1064         }
1065         
1066         size_t end = result.end;
1067         size_t length = end - result.start;
1068         list.append(jsSubstring(exec, s, result.start, length));
1069         if (!length)
1070             ++end;
1071         result = regExpConstructor->performMatch(*vm, regExp, string, s, end);
1072     }
1073     if (list.isEmpty()) {
1074         // if there are no matches at all, it's important to return
1075         // Null instead of an empty array, because this matches
1076         // other browsers and because Null is a false value.
1077         return JSValue::encode(jsNull());
1078     }
1079
1080     return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
1081 }
1082
1083 EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
1084 {
1085     JSValue thisValue = exec->thisValue();
1086     if (!checkObjectCoercible(thisValue))
1087         return throwVMTypeError(exec);
1088     String s = thisValue.toString(exec)->value(exec);
1089     if (exec->hadException())
1090         return JSValue::encode(jsUndefined());
1091
1092     int len = s.length();
1093     RELEASE_ASSERT(len >= 0);
1094
1095     JSValue a0 = exec->argument(0);
1096     JSValue a1 = exec->argument(1);
1097
1098     // The arg processing is very much like ArrayProtoFunc::Slice
1099     double start = a0.toInteger(exec);
1100     double end = a1.isUndefined() ? len : a1.toInteger(exec);
1101     double from = start < 0 ? len + start : start;
1102     double to = end < 0 ? len + end : end;
1103     if (to > from && to > 0 && from < len) {
1104         if (from < 0)
1105             from = 0;
1106         if (to > len)
1107             to = len;
1108         return JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
1109     }
1110
1111     return JSValue::encode(jsEmptyString(exec));
1112 }
1113
1114 // Return true in case of early return (resultLength got to limitLength).
1115 template<typename CharacterType>
1116 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)
1117 {
1118     // 12. Let q = p.
1119     size_t matchPosition;
1120     const CharacterType* characters = string->characters<CharacterType>();
1121     // 13. Repeat, while q != s
1122     //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1123     //   b. If z is failure, then let q = q+1.
1124     //   c. Else, z is not failure
1125     while ((matchPosition = WTF::find(characters, string->length(), separatorCharacter, position)) != notFound) {
1126         // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1127         //    through q (exclusive).
1128         // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1129         //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1130         result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
1131         // 3. Increment lengthA by 1.
1132         // 4. If lengthA == lim, return A.
1133         if (++resultLength == limitLength)
1134             return true;
1135
1136         // 5. Let p = e.
1137         // 8. Let q = p.
1138         position = matchPosition + 1;
1139     }
1140     return false;
1141 }
1142
1143 // ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
1144 EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
1145 {
1146     // 1. Call CheckObjectCoercible passing the this value as its argument.
1147     JSValue thisValue = exec->thisValue();
1148     if (!checkObjectCoercible(thisValue))
1149         return throwVMTypeError(exec);
1150
1151     // 2. Let S be the result of calling ToString, giving it the this value as its argument.
1152     // 6. Let s be the number of characters in S.
1153     String input = thisValue.toString(exec)->value(exec);
1154     if (exec->hadException())
1155         return JSValue::encode(jsUndefined());
1156     ASSERT(!input.isNull());
1157
1158     // 3. Let A be a new array created as if by the expression new Array()
1159     //    where Array is the standard built-in constructor with that name.
1160     JSArray* result = constructEmptyArray(exec, 0);
1161
1162     // 4. Let lengthA be 0.
1163     unsigned resultLength = 0;
1164
1165     // 5. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
1166     JSValue limitValue = exec->argument(1);
1167     unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
1168
1169     // 7. Let p = 0.
1170     size_t position = 0;
1171
1172     // 8. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
1173     //    otherwise let R = ToString(separator).
1174     JSValue separatorValue = exec->argument(0);
1175     if (separatorValue.inherits(RegExpObject::info())) {
1176         VM* vm = &exec->vm();
1177         RegExp* reg = asRegExpObject(separatorValue)->regExp();
1178
1179         // 9. If lim == 0, return A.
1180         if (!limit)
1181             return JSValue::encode(result);
1182
1183         // 10. If separator is undefined, then
1184         if (separatorValue.isUndefined()) {
1185             // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1186             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1187             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1188             // b. Return A.
1189             return JSValue::encode(result);
1190         }
1191
1192         // 11. If s == 0, then
1193         if (input.isEmpty()) {
1194             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1195             // b. If z is not failure, return A.
1196             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1197             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1198             // d. Return A.
1199             if (!reg->match(*vm, input, 0))
1200                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1201             return JSValue::encode(result);
1202         }
1203
1204         // 12. Let q = p.
1205         size_t matchPosition = 0;
1206         // 13. Repeat, while q != s
1207         while (matchPosition < input.length()) {
1208             // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1209             Vector<int, 32> ovector;
1210             int mpos = reg->match(*vm, input, matchPosition, ovector);
1211
1212             // b. If z is a failure then we can break because there are no matches
1213             if (mpos < 0)
1214                 break;
1215             matchPosition = mpos;
1216
1217             // if the match is the empty match at the end, break.
1218             if (matchPosition >= input.length())
1219                 break;
1220
1221             // c. Else, z is not failure
1222             // i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
1223             size_t matchEnd = ovector[1];
1224
1225             // ii. If e == p, then let q = q + 1.
1226             if (matchEnd == position) {
1227                 ++matchPosition;
1228                 continue;
1229             }
1230             // iii. if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
1231             ASSERT(matchEnd);
1232
1233             // iii. Else, e != p
1234
1235             // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1236             //    through q (exclusive).
1237             // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1238             //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1239             result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
1240
1241             // 3. Increment lengthA by 1.
1242             // 4. If lengthA == lim, return A.
1243             ++resultLength;
1244             if (resultLength == limit)
1245                 return JSValue::encode(result);
1246             if (resultLength >= MAX_STORAGE_VECTOR_INDEX) {
1247                 // Let's consider what's best for users here. We're about to increase the length of
1248                 // the split array beyond the maximum length that we can support efficiently. This
1249                 // will cause us to use a HashMap for the new entries after this point. That's going
1250                 // to result in a very long running time of this function and very large memory
1251                 // usage. In my experiments, JSC will sit spinning for minutes after getting here and
1252                 // it was using >4GB of memory and eventually grew to 8GB. It kept running without
1253                 // finishing until I killed it. That's probably not what the user wanted. The user,
1254                 // or the program that the user is running, probably made a mistake by calling this
1255                 // method in such a way that it resulted in such an obnoxious array. Therefore, to
1256                 // protect ourselves, we bail at this point.
1257                 throwOutOfMemoryError(exec);
1258                 return JSValue::encode(jsUndefined());
1259             }
1260
1261             // 5. Let p = e.
1262             // 8. Let q = p.
1263             position = matchEnd;
1264             matchPosition = matchEnd;
1265
1266             // 6. Let i = 0.
1267             // 7. Repeat, while i is not equal to the number of elements in cap.
1268             //  a Let i = i + 1.
1269             for (unsigned i = 1; i <= reg->numSubpatterns(); ++i) {
1270                 // b Call the [[DefineOwnProperty]] internal method of A with arguments
1271                 //   ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
1272                 //   true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1273                 int sub = ovector[i * 2];
1274                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
1275                 // c Increment lengthA by 1.
1276                 // d If lengthA == lim, return A.
1277                 if (++resultLength == limit)
1278                     return JSValue::encode(result);
1279             }
1280         }
1281     } else {
1282         String separator = separatorValue.toString(exec)->value(exec);
1283         if (exec->hadException())
1284             return JSValue::encode(jsUndefined());
1285
1286         // 9. If lim == 0, return A.
1287         if (!limit)
1288             return JSValue::encode(result);
1289
1290         // 10. If separator is undefined, then
1291         JSValue separatorValue = exec->argument(0);
1292         if (separatorValue.isUndefined()) {
1293             // a.  Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1294             //     Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1295             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1296             // b.  Return A.
1297             return JSValue::encode(result);
1298         }
1299
1300         // 11. If s == 0, then
1301         if (input.isEmpty()) {
1302             // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
1303             // b. If z is not failure, return A.
1304             // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
1305             //    Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1306             // d. Return A.
1307             if (!separator.isEmpty())
1308                 result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
1309             return JSValue::encode(result);
1310         }
1311
1312         // Optimized case for splitting on the empty string.
1313         if (separator.isEmpty()) {
1314             limit = std::min(limit, input.length());
1315             // Zero limt/input length handled in steps 9/11 respectively, above.
1316             ASSERT(limit);
1317
1318             do {
1319                 result->putDirectIndex(exec, position, jsSingleCharacterString(exec, input[position]));
1320             } while (++position < limit);
1321
1322             return JSValue::encode(result);
1323         }
1324
1325         // 3 cases:
1326         // -separator length == 1, 8 bits
1327         // -separator length == 1, 16 bits
1328         // -separator length > 1
1329         StringImpl* stringImpl = input.impl();
1330         StringImpl* separatorImpl = separator.impl();
1331         size_t separatorLength = separatorImpl->length();
1332
1333         if (separatorLength == 1) {
1334             UChar separatorCharacter;
1335             if (separatorImpl->is8Bit())
1336                 separatorCharacter = separatorImpl->characters8()[0];
1337             else
1338                 separatorCharacter = separatorImpl->characters16()[0];
1339
1340             if (stringImpl->is8Bit()) {
1341                 if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
1342                     return JSValue::encode(result);
1343             } else {
1344                 if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
1345                     return JSValue::encode(result);
1346             }
1347         } else {
1348             // 12. Let q = p.
1349             size_t matchPosition;
1350             // 13. Repeat, while q != s
1351             //   a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
1352             //   b. If z is failure, then let q = q+1.
1353             //   c. Else, z is not failure
1354             while ((matchPosition = stringImpl->find(separatorImpl, position)) != notFound) {
1355                 // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1356                 //    through q (exclusive).
1357                 // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
1358                 //    Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1359                 result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
1360                 // 3. Increment lengthA by 1.
1361                 // 4. If lengthA == lim, return A.
1362                 if (++resultLength == limit)
1363                     return JSValue::encode(result);
1364
1365                 // 5. Let p = e.
1366                 // 8. Let q = p.
1367                 position = matchPosition + separator.length();
1368             }
1369         }
1370     }
1371
1372     // 14. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
1373     //     through s (exclusive).
1374     // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
1375     //     {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
1376     result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
1377
1378     // 16. Return A.
1379     return JSValue::encode(result);
1380 }
1381
1382 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
1383 {
1384     JSValue thisValue = exec->thisValue();
1385     if (!checkObjectCoercible(thisValue))
1386         return throwVMTypeError(exec);
1387     unsigned len;
1388     JSString* jsString = 0;
1389     String uString;
1390     if (thisValue.isString()) {
1391         jsString = jsCast<JSString*>(thisValue.asCell());
1392         len = jsString->length();
1393     } else {
1394         uString = thisValue.toString(exec)->value(exec);
1395         if (exec->hadException())
1396             return JSValue::encode(jsUndefined());
1397         len = uString.length();
1398     }
1399
1400     JSValue a0 = exec->argument(0);
1401     JSValue a1 = exec->argument(1);
1402
1403     double start = a0.toInteger(exec);
1404     double length = a1.isUndefined() ? len : a1.toInteger(exec);
1405     if (start >= len || length <= 0)
1406         return JSValue::encode(jsEmptyString(exec));
1407     if (start < 0) {
1408         start += len;
1409         if (start < 0)
1410             start = 0;
1411     }
1412     if (start + length > len)
1413         length = len - start;
1414     unsigned substringStart = static_cast<unsigned>(start);
1415     unsigned substringLength = static_cast<unsigned>(length);
1416     if (jsString)
1417         return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1418     return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
1419 }
1420
1421 EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
1422 {
1423     SamplingRegion samplingRegion("Doing substringing");
1424     JSValue thisValue = exec->thisValue();
1425     if (!checkObjectCoercible(thisValue))
1426         return throwVMTypeError(exec);
1427
1428     JSString* jsString = thisValue.toString(exec);
1429     if (exec->hadException())
1430         return JSValue::encode(jsUndefined());
1431
1432     JSValue a0 = exec->argument(0);
1433     JSValue a1 = exec->argument(1);
1434     int len = jsString->length();
1435     RELEASE_ASSERT(len >= 0);
1436
1437     double start = a0.toNumber(exec);
1438     double end;
1439     if (!(start >= 0)) // check for negative values or NaN
1440         start = 0;
1441     else if (start > len)
1442         start = len;
1443     if (a1.isUndefined())
1444         end = len;
1445     else { 
1446         end = a1.toNumber(exec);
1447         if (!(end >= 0)) // check for negative values or NaN
1448             end = 0;
1449         else if (end > len)
1450             end = len;
1451     }
1452     if (start > end) {
1453         double temp = end;
1454         end = start;
1455         start = temp;
1456     }
1457     unsigned substringStart = static_cast<unsigned>(start);
1458     unsigned substringLength = static_cast<unsigned>(end) - substringStart;
1459     return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
1460 }
1461
1462 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
1463 {
1464     JSValue thisValue = exec->thisValue();
1465     if (!checkObjectCoercible(thisValue))
1466         return throwVMTypeError(exec);
1467     JSString* sVal = thisValue.toString(exec);
1468     const String& s = sVal->value(exec);
1469     String lowercasedString = s.convertToLowercaseWithoutLocale();
1470     if (lowercasedString.impl() == s.impl())
1471         return JSValue::encode(sVal);
1472     return JSValue::encode(jsString(exec, lowercasedString));
1473 }
1474
1475 EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
1476 {
1477     JSValue thisValue = exec->thisValue();
1478     if (!checkObjectCoercible(thisValue))
1479         return throwVMTypeError(exec);
1480     JSString* sVal = thisValue.toString(exec);
1481     const String& s = sVal->value(exec);
1482     String uppercasedString = s.convertToUppercaseWithoutLocale();
1483     if (uppercasedString.impl() == s.impl())
1484         return JSValue::encode(sVal);
1485     return JSValue::encode(jsString(exec, uppercasedString));
1486 }
1487
1488 EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
1489 {
1490     JSValue thisValue = exec->thisValue();
1491     if (!checkObjectCoercible(thisValue))
1492         return throwVMTypeError(exec);
1493     String s = thisValue.toString(exec)->value(exec);
1494     if (exec->hadException())
1495         return JSValue::encode(jsUndefined());
1496
1497     JSValue a0 = exec->argument(0);
1498     String str = a0.toString(exec)->value(exec);
1499     if (exec->hadException())
1500         return JSValue::encode(jsUndefined());
1501     return JSValue::encode(jsNumber(Collator().collate(s, str)));
1502 }
1503
1504 #if ENABLE(INTL)
1505 static EncodedJSValue toLocaleCase(ExecState* state, int32_t (*convertCase)(UChar*, int32_t, const UChar*, int32_t, const char*, UErrorCode*))
1506 {
1507     // 1. Let O be RequireObjectCoercible(this value).
1508     JSValue thisValue = state->thisValue();
1509     if (!checkObjectCoercible(thisValue))
1510         return throwVMTypeError(state);
1511
1512     // 2. Let S be ToString(O).
1513     JSString* sVal = thisValue.toString(state);
1514     const String& s = sVal->value(state);
1515
1516     // 3. ReturnIfAbrupt(S).
1517     if (state->hadException())
1518         return JSValue::encode(jsUndefined());
1519
1520     // Optimization for empty strings.
1521     if (s.isEmpty())
1522         return JSValue::encode(sVal);
1523
1524     // 4. Let requestedLocales be CanonicalizeLocaleList(locales).
1525     Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
1526
1527     // 5. ReturnIfAbrupt(requestedLocales).
1528     if (state->hadException())
1529         return JSValue::encode(jsUndefined());
1530
1531     // 6. Let len be the number of elements in requestedLocales.
1532     size_t len = requestedLocales.size();
1533
1534     // 7. If len > 0, then
1535     // a. Let requestedLocale be the first element of requestedLocales.
1536     // 8. Else
1537     // a. Let requestedLocale be DefaultLocale().
1538     String requestedLocale = len > 0 ? requestedLocales.first() : defaultLocale(*state);
1539
1540     // 9. Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences (6.2.1) removed.
1541     String noExtensionsLocale = removeUnicodeLocaleExtension(requestedLocale);
1542
1543     // 10. Let availableLocales be a List with the language tags of the languages for which the Unicode character database contains language sensitive case mappings.
1544     // Note 1: As of Unicode 5.1, the availableLocales list contains the elements "az", "lt", and "tr".
1545     const HashSet<String> availableLocales({ ASCIILiteral("az"), ASCIILiteral("lt"), ASCIILiteral("tr") });
1546
1547     // 11. Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale).
1548     String locale = bestAvailableLocale(availableLocales, noExtensionsLocale);
1549
1550     // 12. If locale is undefined, let locale be "und".
1551     if (locale.isNull())
1552         locale = ASCIILiteral("und");
1553
1554     CString utf8LocaleBuffer = locale.utf8();
1555     const StringView view(s);
1556     const int32_t viewLength = view.length();
1557
1558     // Delegate the following steps to icu u_strToLower or u_strToUpper.
1559     // 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.
1560     // 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).
1561     // 15. Let cuList be a new List.
1562     // 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.
1563     // 17. Let L be a String whose elements are, in order, the elements of cuList.
1564
1565     // Most strings lower/upper case will be the same size as original, so try that first.
1566     UErrorCode error(U_ZERO_ERROR);
1567     Vector<UChar> buffer(viewLength);
1568     String lower;
1569     const int32_t resultLength = convertCase(buffer.data(), viewLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
1570     if (U_SUCCESS(error))
1571         lower = String(buffer.data(), resultLength);
1572     else if (error == U_BUFFER_OVERFLOW_ERROR) {
1573         // Converted case needs more space than original. Try again.
1574         UErrorCode error(U_ZERO_ERROR);
1575         Vector<UChar> buffer(resultLength);
1576         convertCase(buffer.data(), resultLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
1577         if (U_FAILURE(error))
1578             return throwVMTypeError(state, u_errorName(error));
1579         lower = String(buffer.data(), resultLength);
1580     } else
1581         return throwVMTypeError(state, u_errorName(error));
1582
1583     // 18. Return L.
1584     return JSValue::encode(jsString(state, lower));
1585 }
1586
1587 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleLowerCase(ExecState* state)
1588 {
1589     // 13.1.2 String.prototype.toLocaleLowerCase ([locales])
1590     // http://ecma-international.org/publications/standards/Ecma-402.htm
1591     return toLocaleCase(state, u_strToLower);
1592 }
1593
1594 EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleUpperCase(ExecState* state)
1595 {
1596     // 13.1.3 String.prototype.toLocaleUpperCase ([locales])
1597     // http://ecma-international.org/publications/standards/Ecma-402.htm
1598     // 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.
1599     return toLocaleCase(state, u_strToUpper);
1600 }
1601 #endif // ENABLE(INTL)
1602
1603 EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
1604 {
1605     JSValue thisValue = exec->thisValue();
1606     if (!checkObjectCoercible(thisValue))
1607         return throwVMTypeError(exec);
1608     String s = thisValue.toString(exec)->value(exec);
1609     if (exec->hadException())
1610         return JSValue::encode(jsUndefined());
1611     return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
1612 }
1613
1614 EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
1615 {
1616     JSValue thisValue = exec->thisValue();
1617     if (!checkObjectCoercible(thisValue))
1618         return throwVMTypeError(exec);
1619     String s = thisValue.toString(exec)->value(exec);
1620     if (exec->hadException())
1621         return JSValue::encode(jsUndefined());
1622     return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
1623 }
1624
1625 EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
1626 {
1627     JSValue thisValue = exec->thisValue();
1628     if (!checkObjectCoercible(thisValue))
1629         return throwVMTypeError(exec);
1630     String s = thisValue.toString(exec)->value(exec);
1631     if (exec->hadException())
1632         return JSValue::encode(jsUndefined());
1633     return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
1634 }
1635
1636 EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
1637 {
1638     JSValue thisValue = exec->thisValue();
1639     if (!checkObjectCoercible(thisValue))
1640         return throwVMTypeError(exec);
1641     String s = thisValue.toString(exec)->value(exec);
1642     if (exec->hadException())
1643         return JSValue::encode(jsUndefined());
1644     return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
1645 }
1646
1647 EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
1648 {
1649     JSValue thisValue = exec->thisValue();
1650     if (!checkObjectCoercible(thisValue))
1651         return throwVMTypeError(exec);
1652     String s = thisValue.toString(exec)->value(exec);
1653     if (exec->hadException())
1654         return JSValue::encode(jsUndefined());
1655     return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
1656 }
1657
1658 EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
1659 {
1660     JSValue thisValue = exec->thisValue();
1661     if (!checkObjectCoercible(thisValue))
1662         return throwVMTypeError(exec);
1663     String s = thisValue.toString(exec)->value(exec);
1664     if (exec->hadException())
1665         return JSValue::encode(jsUndefined());
1666     return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
1667 }
1668
1669 EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
1670 {
1671     JSValue thisValue = exec->thisValue();
1672     if (!checkObjectCoercible(thisValue))
1673         return throwVMTypeError(exec);
1674     String s = thisValue.toString(exec)->value(exec);
1675     if (exec->hadException())
1676         return JSValue::encode(jsUndefined());
1677     return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
1678 }
1679
1680 EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
1681 {
1682     JSValue thisValue = exec->thisValue();
1683     if (!checkObjectCoercible(thisValue))
1684         return throwVMTypeError(exec);
1685     String s = thisValue.toString(exec)->value(exec);
1686     if (exec->hadException())
1687         return JSValue::encode(jsUndefined());
1688     return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
1689 }
1690
1691 EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
1692 {
1693     JSValue thisValue = exec->thisValue();
1694     if (!checkObjectCoercible(thisValue))
1695         return throwVMTypeError(exec);
1696     String s = thisValue.toString(exec)->value(exec);
1697     if (exec->hadException())
1698         return JSValue::encode(jsUndefined());
1699     return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
1700 }
1701
1702 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
1703 {
1704     JSValue thisValue = exec->thisValue();
1705     if (!checkObjectCoercible(thisValue))
1706         return throwVMTypeError(exec);
1707     String s = thisValue.toString(exec)->value(exec);
1708     if (exec->hadException())
1709         return JSValue::encode(jsUndefined());
1710
1711     JSValue a0 = exec->argument(0);
1712     String color = a0.toWTFString(exec);
1713     color.replaceWithLiteral('"', "&quot;");
1714
1715     return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", color, "\">", s, "</font>"));
1716 }
1717
1718 EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
1719 {
1720     JSValue thisValue = exec->thisValue();
1721     if (!checkObjectCoercible(thisValue))
1722         return throwVMTypeError(exec);
1723     String s = thisValue.toString(exec)->value(exec);
1724     if (exec->hadException())
1725         return JSValue::encode(jsUndefined());
1726
1727     JSValue a0 = exec->argument(0);
1728
1729     uint32_t smallInteger;
1730     if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
1731         unsigned stringSize = s.length();
1732         unsigned bufferSize = 22 + stringSize;
1733         // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
1734         UChar* buffer;
1735         PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1736         if (!impl)
1737             return JSValue::encode(jsUndefined());
1738         buffer[0] = '<';
1739         buffer[1] = 'f';
1740         buffer[2] = 'o';
1741         buffer[3] = 'n';
1742         buffer[4] = 't';
1743         buffer[5] = ' ';
1744         buffer[6] = 's';
1745         buffer[7] = 'i';
1746         buffer[8] = 'z';
1747         buffer[9] = 'e';
1748         buffer[10] = '=';
1749         buffer[11] = '"';
1750         buffer[12] = '0' + smallInteger;
1751         buffer[13] = '"';
1752         buffer[14] = '>';
1753         StringView(s).getCharactersWithUpconvert(&buffer[15]);
1754         buffer[15 + stringSize] = '<';
1755         buffer[16 + stringSize] = '/';
1756         buffer[17 + stringSize] = 'f';
1757         buffer[18 + stringSize] = 'o';
1758         buffer[19 + stringSize] = 'n';
1759         buffer[20 + stringSize] = 't';
1760         buffer[21 + stringSize] = '>';
1761         return JSValue::encode(jsNontrivialString(exec, impl));
1762     }
1763
1764     String fontSize = a0.toWTFString(exec);
1765     fontSize.replaceWithLiteral('"', "&quot;");
1766
1767     return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", fontSize, "\">", s, "</font>"));
1768 }
1769
1770 EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
1771 {
1772     JSValue thisValue = exec->thisValue();
1773     if (!checkObjectCoercible(thisValue))
1774         return throwVMTypeError(exec);
1775     String s = thisValue.toString(exec)->value(exec);
1776     if (exec->hadException())
1777         return JSValue::encode(jsUndefined());
1778
1779     JSValue a0 = exec->argument(0);
1780     String anchor = a0.toWTFString(exec);
1781     anchor.replaceWithLiteral('"', "&quot;");
1782
1783     return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", anchor, "\">", s, "</a>"));
1784 }
1785
1786 EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
1787 {
1788     JSValue thisValue = exec->thisValue();
1789     if (!checkObjectCoercible(thisValue))
1790         return throwVMTypeError(exec);
1791     String s = thisValue.toString(exec)->value(exec);
1792     if (exec->hadException())
1793         return JSValue::encode(jsUndefined());
1794
1795     JSValue a0 = exec->argument(0);
1796     String linkText = a0.toWTFString(exec);
1797     linkText.replaceWithLiteral('"', "&quot;");
1798
1799     unsigned linkTextSize = linkText.length();
1800     unsigned stringSize = s.length();
1801     unsigned bufferSize = 15 + linkTextSize + stringSize;
1802     // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
1803     UChar* buffer;
1804     PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
1805     if (!impl)
1806         return JSValue::encode(jsUndefined());
1807     buffer[0] = '<';
1808     buffer[1] = 'a';
1809     buffer[2] = ' ';
1810     buffer[3] = 'h';
1811     buffer[4] = 'r';
1812     buffer[5] = 'e';
1813     buffer[6] = 'f';
1814     buffer[7] = '=';
1815     buffer[8] = '"';
1816     StringView(linkText).getCharactersWithUpconvert(&buffer[9]);
1817     buffer[9 + linkTextSize] = '"';
1818     buffer[10 + linkTextSize] = '>';
1819     StringView(s).getCharactersWithUpconvert(&buffer[11 + linkTextSize]);
1820     buffer[11 + linkTextSize + stringSize] = '<';
1821     buffer[12 + linkTextSize + stringSize] = '/';
1822     buffer[13 + linkTextSize + stringSize] = 'a';
1823     buffer[14 + linkTextSize + stringSize] = '>';
1824     return JSValue::encode(jsNontrivialString(exec, impl));
1825 }
1826
1827 enum {
1828     TrimLeft = 1,
1829     TrimRight = 2
1830 };
1831
1832 static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
1833 {
1834     if (!checkObjectCoercible(thisValue))
1835         return throwTypeError(exec);
1836     String str = thisValue.toString(exec)->value(exec);
1837     if (exec->hadException())
1838         return jsUndefined();
1839
1840     unsigned left = 0;
1841     if (trimKind & TrimLeft) {
1842         while (left < str.length() && isStrWhiteSpace(str[left]))
1843             left++;
1844     }
1845     unsigned right = str.length();
1846     if (trimKind & TrimRight) {
1847         while (right > left && isStrWhiteSpace(str[right - 1]))
1848             right--;
1849     }
1850
1851     // Don't gc allocate a new string if we don't have to.
1852     if (left == 0 && right == str.length() && thisValue.isString())
1853         return thisValue;
1854
1855     return jsString(exec, str.substringSharingImpl(left, right - left));
1856 }
1857
1858 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
1859 {
1860     JSValue thisValue = exec->thisValue();
1861     return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
1862 }
1863
1864 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
1865 {
1866     JSValue thisValue = exec->thisValue();
1867     return JSValue::encode(trimString(exec, thisValue, TrimLeft));
1868 }
1869
1870 EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
1871 {
1872     JSValue thisValue = exec->thisValue();
1873     return JSValue::encode(trimString(exec, thisValue, TrimRight));
1874 }
1875
1876 static inline unsigned clampAndTruncateToUnsigned(double value, unsigned min, unsigned max)
1877 {
1878     if (value < min)
1879         return min;
1880     if (value > max)
1881         return max;
1882     return static_cast<unsigned>(value);
1883 }
1884
1885 EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
1886 {
1887     JSValue thisValue = exec->thisValue();
1888     if (!checkObjectCoercible(thisValue))
1889         return throwVMTypeError(exec);
1890
1891     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1892     if (exec->hadException())
1893         return JSValue::encode(jsUndefined());
1894
1895     JSValue a0 = exec->argument(0);
1896     if (jsDynamicCast<RegExpObject*>(a0))
1897         return throwVMTypeError(exec);
1898
1899     String searchString = a0.toString(exec)->value(exec);
1900     if (exec->hadException())
1901         return JSValue::encode(jsUndefined());
1902
1903     JSValue positionArg = exec->argument(1);
1904     unsigned start = 0;
1905     if (positionArg.isInt32())
1906         start = std::max(0, positionArg.asInt32());
1907     else {
1908         unsigned length = stringToSearchIn.length();
1909         start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
1910         if (exec->hadException())
1911             return JSValue::encode(jsUndefined());
1912     }
1913
1914     return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixStartingAt(searchString, start)));
1915 }
1916
1917 EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec)
1918 {
1919     JSValue thisValue = exec->thisValue();
1920     if (!checkObjectCoercible(thisValue))
1921         return throwVMTypeError(exec);
1922
1923     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1924     if (exec->hadException())
1925         return JSValue::encode(jsUndefined());
1926
1927     JSValue a0 = exec->argument(0);
1928     if (jsDynamicCast<RegExpObject*>(a0))
1929         return throwVMTypeError(exec);
1930
1931     String searchString = a0.toString(exec)->value(exec);
1932     if (exec->hadException())
1933         return JSValue::encode(jsUndefined());
1934
1935     unsigned length = stringToSearchIn.length();
1936
1937     JSValue endPositionArg = exec->argument(1);
1938     unsigned end = length;
1939     if (endPositionArg.isInt32())
1940         end = std::max(0, endPositionArg.asInt32());
1941     else if (!endPositionArg.isUndefined()) {
1942         end = clampAndTruncateToUnsigned(endPositionArg.toInteger(exec), 0, length);
1943         if (exec->hadException())
1944             return JSValue::encode(jsUndefined());
1945     }
1946
1947     return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, std::min(end, length))));
1948 }
1949
1950 EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
1951 {
1952     JSValue thisValue = exec->thisValue();
1953     if (!checkObjectCoercible(thisValue))
1954         return throwVMTypeError(exec);
1955
1956     String stringToSearchIn = thisValue.toString(exec)->value(exec);
1957     if (exec->hadException())
1958         return JSValue::encode(jsUndefined());
1959
1960     JSValue a0 = exec->argument(0);
1961     if (jsDynamicCast<RegExpObject*>(a0))
1962         return throwVMTypeError(exec);
1963
1964     String searchString = a0.toString(exec)->value(exec);
1965     if (exec->hadException())
1966         return JSValue::encode(jsUndefined());
1967
1968     JSValue positionArg = exec->argument(1);
1969     unsigned start = 0;
1970     if (positionArg.isInt32())
1971         start = std::max(0, positionArg.asInt32());
1972     else {
1973         unsigned length = stringToSearchIn.length();
1974         start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
1975         if (exec->hadException())
1976             return JSValue::encode(jsUndefined());
1977     }
1978
1979     return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
1980 }
1981
1982 EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState* exec)
1983 {
1984     JSValue thisValue = exec->thisValue();
1985     if (!checkObjectCoercible(thisValue))
1986         return throwVMTypeError(exec);
1987     JSString* string = thisValue.toString(exec);
1988     return JSValue::encode(JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), string));
1989 }
1990
1991 static JSValue normalize(ExecState* exec, const UChar* source, size_t sourceLength, UNormalizationMode form)
1992 {
1993     UErrorCode status = U_ZERO_ERROR;
1994     int32_t normalizedStringLength = unorm_normalize(source, sourceLength, form, 0, nullptr, 0, &status);
1995
1996     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
1997         // The behavior is not specified when normalize fails.
1998         // Now we throw a type erorr since it seems that the contents of the string are invalid.
1999         return throwTypeError(exec);
2000     }
2001
2002     UChar* buffer = nullptr;
2003     RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(normalizedStringLength, buffer);
2004     if (!impl)
2005         return throwOutOfMemoryError(exec);
2006
2007     status = U_ZERO_ERROR;
2008     unorm_normalize(source, sourceLength, form, 0, buffer, normalizedStringLength, &status);
2009     if (U_FAILURE(status))
2010         return throwTypeError(exec);
2011
2012     return jsString(exec, impl.release());
2013 }
2014
2015 EncodedJSValue JSC_HOST_CALL stringProtoFuncNormalize(ExecState* exec)
2016 {
2017     JSValue thisValue = exec->thisValue();
2018     if (!checkObjectCoercible(thisValue))
2019         return throwVMTypeError(exec);
2020     JSString::SafeView source = thisValue.toString(exec)->view(exec);
2021     if (exec->hadException())
2022         return JSValue::encode(jsUndefined());
2023
2024     UNormalizationMode form = UNORM_NFC;
2025     // Verify that the argument is provided and is not undefined.
2026     if (!exec->argument(0).isUndefined()) {
2027         String formString = exec->uncheckedArgument(0).toString(exec)->value(exec);
2028         if (exec->hadException())
2029             return JSValue::encode(jsUndefined());
2030
2031         if (formString == "NFC")
2032             form = UNORM_NFC;
2033         else if (formString == "NFD")
2034             form = UNORM_NFD;
2035         else if (formString == "NFKC")
2036             form = UNORM_NFKC;
2037         else if (formString == "NFKD")
2038             form = UNORM_NFKD;
2039         else
2040             return throwVMError(exec, createRangeError(exec, ASCIILiteral("argument does not match any normalization form")));
2041     }
2042
2043     return JSValue::encode(normalize(exec, source.get().upconvertedCharacters(), source.length(), form));
2044 }
2045
2046 } // namespace JSC