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