579d4698257321aa22ce282836ae40f413dfd971
[WebKit-https.git] / Source / JavaScriptCore / runtime / RegExpPrototype.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2007-2008, 2016 Apple Inc. All Rights Reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include "config.h"
22 #include "RegExpPrototype.h"
23
24 #include "ArrayPrototype.h"
25 #include "BuiltinNames.h"
26 #include "Error.h"
27 #include "JSArray.h"
28 #include "JSCBuiltins.h"
29 #include "JSCJSValue.h"
30 #include "JSFunction.h"
31 #include "JSObject.h"
32 #include "JSString.h"
33 #include "JSStringBuilder.h"
34 #include "Lexer.h"
35 #include "ObjectPrototype.h"
36 #include "JSCInlines.h"
37 #include "RegExpObject.h"
38 #include "RegExp.h"
39 #include "RegExpCache.h"
40 #include "RegExpConstructor.h"
41 #include "RegExpMatchesArray.h"
42 #include "StringObject.h"
43 #include "StringRecursionChecker.h"
44
45 namespace JSC {
46
47 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
48 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
49 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
50 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState*);
51 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState*);
53 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterSticky(ExecState*);
54 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterUnicode(ExecState*);
55 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState*);
56 static EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState*);
57
58 const ClassInfo RegExpPrototype::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(RegExpPrototype) };
59
60 RegExpPrototype::RegExpPrototype(VM& vm, Structure* structure)
61     : JSNonFinalObject(vm, structure)
62 {
63 }
64
65 void RegExpPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
66 {
67     Base::finishCreation(vm);
68     ASSERT(inherits(info()));
69     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->compile, regExpProtoFuncCompile, DontEnum, 2);
70     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->exec, regExpProtoFuncExec, DontEnum, 1, RegExpExecIntrinsic);
71     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, regExpProtoFuncToString, DontEnum, 0);
72     JSC_NATIVE_GETTER(vm.propertyNames->global, regExpProtoGetterGlobal, DontEnum | Accessor);
73     JSC_NATIVE_GETTER(vm.propertyNames->ignoreCase, regExpProtoGetterIgnoreCase, DontEnum | Accessor);
74     JSC_NATIVE_GETTER(vm.propertyNames->multiline, regExpProtoGetterMultiline, DontEnum | Accessor);
75     JSC_NATIVE_GETTER(vm.propertyNames->sticky, regExpProtoGetterSticky, DontEnum | Accessor);
76     JSC_NATIVE_GETTER(vm.propertyNames->unicode, regExpProtoGetterUnicode, DontEnum | Accessor);
77     JSC_NATIVE_GETTER(vm.propertyNames->source, regExpProtoGetterSource, DontEnum | Accessor);
78     JSC_NATIVE_GETTER(vm.propertyNames->flags, regExpProtoGetterFlags, DontEnum | Accessor);
79     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->matchSymbol, regExpPrototypeMatchCodeGenerator, DontEnum);
80     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->replaceSymbol, regExpPrototypeReplaceCodeGenerator, DontEnum);
81     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->searchSymbol, regExpPrototypeSearchCodeGenerator, DontEnum);
82     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->splitSymbol, regExpPrototypeSplitCodeGenerator, DontEnum);
83     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->test, regExpPrototypeTestCodeGenerator, DontEnum);
84
85     m_emptyRegExp.set(vm, this, RegExp::create(vm, "", NoFlags));
86 }
87
88 void RegExpPrototype::visitChildren(JSCell* cell, SlotVisitor& visitor)
89 {
90     RegExpPrototype* thisObject = jsCast<RegExpPrototype*>(cell);
91     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
92     Base::visitChildren(thisObject, visitor);
93     
94     visitor.append(&thisObject->m_emptyRegExp);
95 }
96
97 // ------------------------------ Functions ---------------------------
98
99 EncodedJSValue JSC_HOST_CALL regExpProtoFuncTestFast(ExecState* exec)
100 {
101     JSValue thisValue = exec->thisValue();
102     if (!thisValue.inherits(RegExpObject::info()))
103         return throwVMTypeError(exec);
104     JSString* string = exec->argument(0).toStringOrNull(exec);
105     if (!string)
106         return JSValue::encode(jsUndefined());
107     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->lexicalGlobalObject(), string)));
108 }
109
110 EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
111 {
112     JSValue thisValue = exec->thisValue();
113     if (!thisValue.inherits(RegExpObject::info()))
114         return throwVMTypeError(exec, "Builtin RegExp exec can only be called on a RegExp object");
115     JSString* string = exec->argument(0).toStringOrNull(exec);
116     if (!string)
117         return JSValue::encode(jsUndefined());
118     return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->lexicalGlobalObject(), string));
119 }
120
121 EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchFast(ExecState* exec)
122 {
123     JSValue thisValue = exec->thisValue();
124     if (!thisValue.inherits(RegExpObject::info()))
125         return throwVMTypeError(exec);
126     JSString* string = exec->argument(0).toStringOrNull(exec);
127     if (!string)
128         return JSValue::encode(jsUndefined());
129     if (!asRegExpObject(thisValue)->regExp()->global())
130         return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->lexicalGlobalObject(), string));
131     return JSValue::encode(asRegExpObject(thisValue)->matchGlobal(exec, exec->lexicalGlobalObject(), string));
132 }
133
134 EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
135 {
136     JSValue thisValue = exec->thisValue();
137     if (!thisValue.inherits(RegExpObject::info()))
138         return throwVMTypeError(exec);
139
140     RegExp* regExp;
141     JSValue arg0 = exec->argument(0);
142     JSValue arg1 = exec->argument(1);
143     
144     if (arg0.inherits(RegExpObject::info())) {
145         if (!arg1.isUndefined())
146             return throwVMError(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another.")));
147         regExp = asRegExpObject(arg0)->regExp();
148     } else {
149         String pattern = !exec->argumentCount() ? emptyString() : arg0.toString(exec)->value(exec);
150         if (exec->hadException())
151             return JSValue::encode(jsUndefined());
152
153         RegExpFlags flags = NoFlags;
154         if (!arg1.isUndefined()) {
155             flags = regExpFlags(arg1.toString(exec)->value(exec));
156             if (exec->hadException())
157                 return JSValue::encode(jsUndefined());
158             if (flags == InvalidFlags)
159                 return throwVMError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor.")));
160         }
161         regExp = RegExp::create(exec->vm(), pattern, flags);
162     }
163
164     if (!regExp->isValid())
165         return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
166
167     asRegExpObject(thisValue)->setRegExp(exec->vm(), regExp);
168     asRegExpObject(thisValue)->setLastIndex(exec, 0);
169     return JSValue::encode(jsUndefined());
170 }
171
172 typedef std::array<char, 5 + 1> FlagsString; // 5 different flags and a null character terminator.
173
174 static inline FlagsString flagsString(ExecState* exec, JSObject* regexp)
175 {
176     FlagsString string;
177     string[0] = 0;
178
179     VM& vm = exec->vm();
180
181     JSValue globalValue = regexp->get(exec, exec->propertyNames().global);
182     if (vm.exception())
183         return string;
184     JSValue ignoreCaseValue = regexp->get(exec, exec->propertyNames().ignoreCase);
185     if (vm.exception())
186         return string;
187     JSValue multilineValue = regexp->get(exec, exec->propertyNames().multiline);
188     if (vm.exception())
189         return string;
190     JSValue unicodeValue = regexp->get(exec, exec->propertyNames().unicode);
191     if (vm.exception())
192         return string;
193     JSValue stickyValue = regexp->get(exec, exec->propertyNames().sticky);
194     if (vm.exception())
195         return string;
196
197     unsigned index = 0;
198     if (globalValue.toBoolean(exec))
199         string[index++] = 'g';
200     if (ignoreCaseValue.toBoolean(exec))
201         string[index++] = 'i';
202     if (multilineValue.toBoolean(exec))
203         string[index++] = 'm';
204     if (unicodeValue.toBoolean(exec))
205         string[index++] = 'u';
206     if (stickyValue.toBoolean(exec))
207         string[index++] = 'y';
208     ASSERT(index < string.size());
209     string[index] = 0;
210     return string;
211 }
212
213 EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec)
214 {
215     JSValue thisValue = exec->thisValue();
216     if (!thisValue.isObject())
217         return throwVMTypeError(exec);
218
219     JSObject* thisObject = asObject(thisValue);
220
221     StringRecursionChecker checker(exec, thisObject);
222     if (JSValue earlyReturnValue = checker.earlyReturnValue())
223         return JSValue::encode(earlyReturnValue);
224
225     VM& vm = exec->vm();
226     JSValue sourceValue = thisObject->get(exec, vm.propertyNames->source);
227     if (vm.exception())
228         return JSValue::encode(jsUndefined());
229     String source = sourceValue.toString(exec)->value(exec);
230     if (vm.exception())
231         return JSValue::encode(jsUndefined());
232
233     JSValue flagsValue = thisObject->get(exec, vm.propertyNames->flags);
234     if (vm.exception())
235         return JSValue::encode(jsUndefined());
236     String flags = flagsValue.toString(exec)->value(exec);
237     if (vm.exception())
238         return JSValue::encode(jsUndefined());
239
240     return JSValue::encode(jsMakeNontrivialString(exec, '/', source, '/', flags));
241 }
242
243 EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState* exec)
244 {
245     JSValue thisValue = exec->thisValue();
246     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
247         if (thisValue.inherits(RegExpPrototype::info()))
248             return JSValue::encode(jsUndefined());
249         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.global getter can only be called on a RegExp object"));
250     }
251
252     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->global()));
253 }
254
255 EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState* exec)
256 {
257     JSValue thisValue = exec->thisValue();
258     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
259         if (thisValue.inherits(RegExpPrototype::info()))
260             return JSValue::encode(jsUndefined());
261         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.ignoreCase getter can only be called on a RegExp object"));
262     }
263
264     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->ignoreCase()));
265 }
266
267 EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState* exec)
268 {
269     JSValue thisValue = exec->thisValue();
270     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
271         if (thisValue.inherits(RegExpPrototype::info()))
272             return JSValue::encode(jsUndefined());
273         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.multiline getter can only be called on a RegExp object"));
274     }
275
276     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->multiline()));
277 }
278
279 EncodedJSValue JSC_HOST_CALL regExpProtoGetterSticky(ExecState* exec)
280 {
281     JSValue thisValue = exec->thisValue();
282     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
283         if (thisValue.inherits(RegExpPrototype::info()))
284             return JSValue::encode(jsUndefined());
285         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.sticky getter can only be called on a RegExp object"));
286     }
287     
288     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->sticky()));
289 }
290
291 EncodedJSValue JSC_HOST_CALL regExpProtoGetterUnicode(ExecState* exec)
292 {
293     JSValue thisValue = exec->thisValue();
294     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
295         if (thisValue.inherits(RegExpPrototype::info()))
296             return JSValue::encode(jsUndefined());
297         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.unicode getter can only be called on a RegExp object"));
298     }
299     
300     return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->unicode()));
301 }
302
303 EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState* exec)
304 {
305     JSValue thisValue = exec->thisValue();
306     if (UNLIKELY(!thisValue.isObject()))
307         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.flags getter can only be called on an object"));
308
309     auto flags = flagsString(exec, asObject(thisValue));
310     if (exec->hadException())
311         return JSValue::encode(jsUndefined());
312
313     return JSValue::encode(jsString(exec, flags.data()));
314 }
315
316 template <typename CharacterType>
317 static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType);
318
319 template <>
320 inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator)
321 {
322     if (lineTerminator == '\n')
323         builder.append('n');
324     else
325         builder.append('r');
326 }
327
328 template <>
329 inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator)
330 {
331     if (lineTerminator == '\n')
332         builder.append('n');
333     else if (lineTerminator == '\r')
334         builder.append('r');
335     else if (lineTerminator == 0x2028)
336         builder.appendLiteral("u2028");
337     else
338         builder.appendLiteral("u2029");
339 }
340
341 template <typename CharacterType>
342 static inline JSValue regExpProtoGetterSourceInternal(ExecState* exec, const String& pattern, const CharacterType* characters, unsigned length)
343 {
344     bool previousCharacterWasBackslash = false;
345     bool inBrackets = false;
346     bool shouldEscape = false;
347
348     // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/',
349     // and also states that the result must be a valid RegularExpressionLiteral. '//' is
350     // not a valid RegularExpressionLiteral (since it is a single line comment), and hence
351     // source cannot ever validly be "". If the source is empty, return a different Pattern
352     // that would match the same thing.
353     if (!length)
354         return jsNontrivialString(exec, ASCIILiteral("(?:)"));
355
356     // early return for strings that don't contain a forwards slash and LineTerminator
357     for (unsigned i = 0; i < length; ++i) {
358         CharacterType ch = characters[i];
359         if (!previousCharacterWasBackslash) {
360             if (inBrackets) {
361                 if (ch == ']')
362                     inBrackets = false;
363             } else {
364                 if (ch == '/') {
365                     shouldEscape = true;
366                     break;
367                 }
368                 if (ch == '[')
369                     inBrackets = true;
370             }
371         }
372
373         if (Lexer<CharacterType>::isLineTerminator(ch)) {
374             shouldEscape = true;
375             break;
376         }
377
378         if (previousCharacterWasBackslash)
379             previousCharacterWasBackslash = false;
380         else
381             previousCharacterWasBackslash = ch == '\\';
382     }
383
384     if (!shouldEscape)
385         return jsString(exec, pattern);
386
387     previousCharacterWasBackslash = false;
388     inBrackets = false;
389     StringBuilder result;
390     for (unsigned i = 0; i < length; ++i) {
391         CharacterType ch = characters[i];
392         if (!previousCharacterWasBackslash) {
393             if (inBrackets) {
394                 if (ch == ']')
395                     inBrackets = false;
396             } else {
397                 if (ch == '/')
398                     result.append('\\');
399                 else if (ch == '[')
400                     inBrackets = true;
401             }
402         }
403
404         // escape LineTerminator
405         if (Lexer<CharacterType>::isLineTerminator(ch)) {
406             if (!previousCharacterWasBackslash)
407                 result.append('\\');
408
409             appendLineTerminatorEscape<CharacterType>(result, ch);
410         } else
411             result.append(ch);
412
413         if (previousCharacterWasBackslash)
414             previousCharacterWasBackslash = false;
415         else
416             previousCharacterWasBackslash = ch == '\\';
417     }
418
419     return jsString(exec, result.toString());
420 }
421
422 EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState* exec)
423 {
424     JSValue thisValue = exec->thisValue();
425     if (UNLIKELY(!thisValue.inherits(RegExpObject::info()))) {
426         if (thisValue.inherits(RegExpPrototype::info()))
427             return JSValue::encode(jsString(exec, ASCIILiteral("(?:)")));
428         return throwVMTypeError(exec, ASCIILiteral("The RegExp.prototype.source getter can only be called on a RegExp object"));
429     }
430
431     String pattern = asRegExpObject(thisValue)->regExp()->pattern();
432     if (pattern.is8Bit())
433         return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters8(), pattern.length()));
434     return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters16(), pattern.length()));
435 }
436
437 EncodedJSValue JSC_HOST_CALL regExpProtoFuncSearchFast(ExecState* exec)
438 {
439     VM& vm = exec->vm();
440     JSValue thisValue = exec->thisValue();
441     RegExp* regExp = asRegExpObject(thisValue)->regExp();
442
443     JSString* string = exec->uncheckedArgument(0).toString(exec);
444     String s = string->value(exec);
445     if (vm.exception())
446         return JSValue::encode(jsUndefined());
447
448     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
449     MatchResult result = regExpConstructor->performMatch(vm, regExp, string, s, 0);
450     return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
451 }
452
453 static inline unsigned advanceStringIndex(String str, unsigned strSize, unsigned index, bool isUnicode)
454 {
455     if (!isUnicode)
456         return ++index;
457     return RegExpObject::advanceStringUnicode(str, strSize, index);
458 }
459
460 // ES 21.2.5.11 RegExp.prototype[@@split](string, limit)
461 EncodedJSValue JSC_HOST_CALL regExpProtoFuncSplitFast(ExecState* exec)
462 {
463     VM& vm = exec->vm();
464
465     // 1. [handled by JS builtin] Let rx be the this value.
466     // 2. [handled by JS builtin] If Type(rx) is not Object, throw a TypeError exception.
467     JSValue thisValue = exec->thisValue();
468     RegExp* regexp = asRegExpObject(thisValue)->regExp();
469
470     // 3. [handled by JS builtin] Let S be ? ToString(string).
471     String input = exec->argument(0).toString(exec)->value(exec);
472     if (vm.exception())
473         return JSValue::encode(jsUndefined());
474     ASSERT(!input.isNull());
475
476     // 4. [handled by JS builtin] Let C be ? SpeciesConstructor(rx, %RegExp%).
477     // 5. [handled by JS builtin] Let flags be ? ToString(? Get(rx, "flags")).
478     // 6. [handled by JS builtin] If flags contains "u", let unicodeMatching be true.
479     // 7. [handled by JS builtin] Else, let unicodeMatching be false.
480     // 8. [handled by JS builtin] If flags contains "y", let newFlags be flags.
481     // 9. [handled by JS builtin] Else, let newFlags be the string that is the concatenation of flags and "y".
482     // 10. [handled by JS builtin] Let splitter be ? Construct(C, « rx, newFlags »).
483
484     // 11. Let A be ArrayCreate(0).
485     // 12. Let lengthA be 0.
486     JSArray* result = constructEmptyArray(exec, 0);
487     unsigned resultLength = 0;
488
489     // 13. If limit is undefined, let lim be 2^32-1; else let lim be ? ToUint32(limit).
490     JSValue limitValue = exec->argument(1);
491     unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
492
493     // 14. Let size be the number of elements in S.
494     unsigned inputSize = input.length();
495
496     // 15. Let p = 0.
497     unsigned position = 0;
498
499     // 16. If lim == 0, return A.
500     if (!limit)
501         return JSValue::encode(result);
502
503     // 17. If size == 0, then
504     if (input.isEmpty()) {
505         // a. Let z be ? RegExpExec(splitter, S).
506         // b. If z is not null, return A.
507         // c. Perform ! CreateDataProperty(A, "0", S).
508         // d. Return A.
509         if (!regexp->match(vm, input, 0))
510             result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input));
511         return JSValue::encode(result);
512     }
513
514     // 18. Let q = p.
515     unsigned matchPosition = position;
516     // 19. Repeat, while q < size
517     bool regExpIsSticky = regexp->sticky();
518     bool regExpIsUnicode = regexp->unicode();
519     while (matchPosition < inputSize) {
520         Vector<int, 32> ovector;
521
522         // a. Perform ? Set(splitter, "lastIndex", q, true).
523         // b. Let z be ? RegExpExec(splitter, S).
524         int mpos = regexp->match(vm, input, matchPosition, ovector);
525
526         // c. If z is null, let q be AdvanceStringIndex(S, q, unicodeMatching).
527         if (mpos < 0) {
528             if (!regExpIsSticky)
529                 break;
530             matchPosition = advanceStringIndex(input, inputSize, matchPosition, regExpIsUnicode);
531             continue;
532         }
533         if (static_cast<unsigned>(mpos) >= inputSize) {
534             // The spec redoes the RegExpExec starting at the next character of the input.
535             // But in our case, mpos < 0 means that the native regexp already searched all permutations
536             // and know that we won't be able to find a match for the separator even if we redo the
537             // RegExpExec starting at the next character of the input. So, just bail.
538             break;
539         }
540
541         // d. Else, z is not null
542         //    i. Let e be ? ToLength(? Get(splitter, "lastIndex")).
543         //   ii. Let e be min(e, size).
544         matchPosition = mpos;
545         unsigned matchEnd = ovector[1];
546
547         //  iii. If e = p, let q be AdvanceStringIndex(S, q, unicodeMatching).
548         if (matchEnd == position) {
549             matchPosition = advanceStringIndex(input, inputSize, matchPosition, regExpIsUnicode);
550             continue;
551         }
552         // if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
553         ASSERT(matchEnd);
554
555         //   iv. Else e != p,
556         {
557             unsigned numberOfCaptures = regexp->numSubpatterns();
558             unsigned newResultLength = resultLength + numberOfCaptures + 1;
559             if (newResultLength < numberOfCaptures || newResultLength >= MAX_STORAGE_VECTOR_INDEX) {
560                 // Let's consider what's best for users here. We're about to increase the length of
561                 // the split array beyond the maximum length that we can support efficiently. This
562                 // will cause us to use a HashMap for the new entries after this point. That's going
563                 // to result in a very long running time of this function and very large memory
564                 // usage. In my experiments, JSC will sit spinning for minutes after getting here and
565                 // it was using >4GB of memory and eventually grew to 8GB. It kept running without
566                 // finishing until I killed it. That's probably not what the user wanted. The user,
567                 // or the program that the user is running, probably made a mistake by calling this
568                 // method in such a way that it resulted in such an obnoxious array. Therefore, to
569                 // protect ourselves, we bail at this point.
570                 throwOutOfMemoryError(exec);
571                 return JSValue::encode(jsUndefined());
572             }
573
574             // 1. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through q (exclusive).
575             // 2. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
576             result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
577
578             // 3. Let lengthA be lengthA + 1.
579             // 4. If lengthA = lim, return A.
580             if (++resultLength == limit)
581                 return JSValue::encode(result);
582
583             // 5. Let p be e.
584             position = matchEnd;
585
586             // 6. Let numberOfCaptures be ? ToLength(? Get(z, "length")).
587             // 7. Let numberOfCaptures be max(numberOfCaptures-1, 0).
588             // 8. Let i be 1.
589             // 9. Repeat, while i <= numberOfCaptures,
590             for (unsigned i = 1; i <= numberOfCaptures; ++i) {
591                 // a. Let nextCapture be ? Get(z, ! ToString(i)).
592                 // b. Perform ! CreateDataProperty(A, ! ToString(lengthA), nextCapture).
593                 int sub = ovector[i * 2];
594                 result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
595
596                 // c. Let i be i + 1.
597                 // d. Let lengthA be lengthA + 1.
598                 // e. If lengthA = lim, return A.
599                 if (++resultLength == limit)
600                     return JSValue::encode(result);
601             }
602
603             // 10. Let q be p.
604             matchPosition = position;
605         }
606     }
607
608     // 20. Let T be a String value equal to the substring of S consisting of the elements at indices p (inclusive) through size (exclusive).
609     // 21. Perform ! CreateDataProperty(A, ! ToString(lengthA), T).
610     result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, inputSize - position));
611
612     // 22. Return A.
613     return JSValue::encode(result);
614 }
615
616 } // namespace JSC