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