summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/regexp-match-all.tq
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/regexp-match-all.tq')
-rw-r--r--deps/v8/src/builtins/regexp-match-all.tq258
1 files changed, 258 insertions, 0 deletions
diff --git a/deps/v8/src/builtins/regexp-match-all.tq b/deps/v8/src/builtins/regexp-match-all.tq
new file mode 100644
index 0000000000..1be6e69afc
--- /dev/null
+++ b/deps/v8/src/builtins/regexp-match-all.tq
@@ -0,0 +1,258 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include 'src/builtins/builtins-regexp-gen.h'
+
+namespace regexp {
+
+ extern transitioning macro RegExpBuiltinsAssembler::RegExpCreate(
+ implicit context: Context)(Context, Object, String): Object;
+
+ extern transitioning macro
+ RegExpMatchAllAssembler::CreateRegExpStringIterator(
+ NativeContext, Object, String, bool, bool): JSAny;
+
+ @export
+ transitioning macro RegExpPrototypeMatchAllImpl(implicit context: Context)(
+ nativeContext: NativeContext, receiver: JSAny, string: JSAny): JSAny {
+ // 1. Let R be the this value.
+ // 2. If Type(R) is not Object, throw a TypeError exception.
+ ThrowIfNotJSReceiver(
+ receiver, kIncompatibleMethodReceiver, 'RegExp.prototype.@@matchAll');
+ const receiver = UnsafeCast<JSReceiver>(receiver);
+
+ // 3. Let S be ? ToString(O).
+ const string: String = ToString_Inline(context, string);
+
+ let matcher: Object;
+ let global: bool;
+ let unicode: bool;
+
+ // 'FastJSRegExp' uses the strict fast path check because following code
+ // uses the flags property.
+ // TODO(jgruber): Handle slow flag accesses on the fast path and make this
+ // permissive.
+ typeswitch (receiver) {
+ case (fastRegExp: FastJSRegExp): {
+ const source = fastRegExp.source;
+
+ // 4. Let C be ? SpeciesConstructor(R, %RegExp%).
+ // 5. Let flags be ? ToString(? Get(R, "flags")).
+ // 6. Let matcher be ? Construct(C, « R, flags »).
+ const flags: String = FastFlagsGetter(fastRegExp);
+ matcher = RegExpCreate(nativeContext, source, flags);
+ const matcherRegExp = UnsafeCast<JSRegExp>(matcher);
+ assert(IsFastRegExpPermissive(matcherRegExp));
+
+ // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
+ // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
+ const fastRegExp = UnsafeCast<FastJSRegExp>(receiver);
+ FastStoreLastIndex(matcherRegExp, fastRegExp.lastIndex);
+
+ // 9. If flags contains "g", let global be true.
+ // 10. Else, let global be false.
+ global = FastFlagGetter(matcherRegExp, kGlobal);
+
+ // 11. If flags contains "u", let fullUnicode be true.
+ // 12. Else, let fullUnicode be false.
+ unicode = FastFlagGetter(matcherRegExp, kUnicode);
+ }
+ case (Object): {
+ // 4. Let C be ? SpeciesConstructor(R, %RegExp%).
+ const regexpFun =
+ UnsafeCast<JSFunction>(nativeContext[REGEXP_FUNCTION_INDEX]);
+ const speciesConstructor =
+ UnsafeCast<Constructor>(SpeciesConstructor(receiver, regexpFun));
+
+ // 5. Let flags be ? ToString(? Get(R, "flags")).
+ const flags = GetProperty(receiver, 'flags');
+ const flagsString = ToString_Inline(context, flags);
+
+ // 6. Let matcher be ? Construct(C, « R, flags »).
+ matcher = Construct(speciesConstructor, receiver, flagsString);
+
+ // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
+ const lastIndex: Number =
+ ToLength_Inline(context, SlowLoadLastIndex(receiver));
+
+ // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
+ SlowStoreLastIndex(UnsafeCast<JSReceiver>(matcher), lastIndex);
+
+ // 9. If flags contains "g", let global be true.
+ // 10. Else, let global be false.
+ const globalCharString: String = StringConstant('g');
+ const globalIndex: Smi =
+ StringIndexOf(flagsString, globalCharString, 0);
+ global = globalIndex != -1;
+
+ // 11. If flags contains "u", let fullUnicode be true.
+ // 12. Else, let fullUnicode be false.
+ const unicodeCharString = StringConstant('u');
+ const unicodeIndex: Smi =
+ StringIndexOf(flagsString, unicodeCharString, 0);
+ unicode = unicodeIndex != -1;
+ }
+ }
+
+ // 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode).
+ return CreateRegExpStringIterator(
+ nativeContext, matcher, string, global, unicode);
+ }
+
+ // https://tc39.github.io/proposal-string-matchall/
+ // RegExp.prototype [ @@matchAll ] ( string )
+ transitioning javascript builtin RegExpPrototypeMatchAll(
+ js-implicit context: Context, receiver: JSAny)(string: JSAny): JSAny {
+ const nativeContext: NativeContext = LoadNativeContext(context);
+ return RegExpPrototypeMatchAllImpl(nativeContext, receiver, string);
+ }
+
+ const kJSRegExpStringIteratorDone:
+ constexpr int31 generates '1 << JSRegExpStringIterator::kDoneBit';
+ const kJSRegExpStringIteratorGlobal: constexpr int31
+ generates '1 << JSRegExpStringIterator::kGlobalBit';
+ const kJSRegExpStringIteratorUnicode: constexpr int31
+ generates '1 << JSRegExpStringIterator::kUnicodeBit';
+
+ extern macro IsSetSmi(Smi, constexpr int31): bool;
+
+ macro HasDoneFlag(flags: Smi): bool {
+ return IsSetSmi(flags, kJSRegExpStringIteratorDone);
+ }
+
+ macro HasGlobalFlag(flags: Smi): bool {
+ return IsSetSmi(flags, kJSRegExpStringIteratorGlobal);
+ }
+
+ macro HasUnicodeFlag(flags: Smi): bool {
+ return IsSetSmi(flags, kJSRegExpStringIteratorUnicode);
+ }
+
+ macro SetDoneFlag(iterator: JSRegExpStringIterator, flags: Smi) {
+ const newFlags: Smi = flags | kJSRegExpStringIteratorDone;
+ iterator.flags = newFlags;
+ }
+
+ extern macro RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
+ implicit context: Context)(JSReceiver, RegExpMatchInfo, String):
+ JSRegExpResult;
+
+ // https://tc39.github.io/proposal-string-matchall/
+ // %RegExpStringIteratorPrototype%.next ( )
+ transitioning javascript builtin RegExpStringIteratorPrototypeNext(
+ js-implicit context: Context, receiver: JSAny)(): JSAny {
+ // 1. Let O be the this value.
+ // 2. If Type(O) is not Object, throw a TypeError exception.
+ // 3. If O does not have all of the internal slots of a RegExp String
+ // Iterator Object Instance (see 5.3), throw a TypeError exception.
+ const methodName: constexpr string =
+ '%RegExpStringIterator%.prototype.next';
+ const receiver = Cast<JSRegExpStringIterator>(receiver) otherwise
+ ThrowTypeError(kIncompatibleMethodReceiver, methodName, receiver);
+
+ try {
+ // 4. If O.[[Done]] is true, then
+ // a. Return ! CreateIterResultObject(undefined, true).
+ const flags: Smi = receiver.flags;
+ if (HasDoneFlag(flags)) goto ReturnEmptyDoneResult;
+
+ // 5. Let R be O.[[iteratingRegExp]].
+ const iteratingRegExp: JSReceiver = receiver.iterating_reg_exp;
+
+ // 6. Let S be O.[[IteratedString]].
+ const iteratingString: String = receiver.iterated_string;
+
+ // 7. Let global be O.[[Global]].
+ // 8. Let fullUnicode be O.[[Unicode]].
+ // 9. Let match be ? RegExpExec(R, S).
+ let match: Object;
+ let isFastRegExp: bool = false;
+ try {
+ if (IsFastRegExpPermissive(iteratingRegExp)) {
+ const matchIndices: RegExpMatchInfo =
+ RegExpPrototypeExecBodyWithoutResultFast(
+ UnsafeCast<JSRegExp>(iteratingRegExp), iteratingString)
+ otherwise IfNoMatch;
+ match = ConstructNewResultFromMatchInfo(
+ iteratingRegExp, matchIndices, iteratingString);
+ isFastRegExp = true;
+ } else {
+ match = RegExpExec(iteratingRegExp, iteratingString);
+ if (match == Null) {
+ goto IfNoMatch;
+ }
+ }
+ // 11. Else,
+ // b. Else, handle non-global case first.
+ if (!HasGlobalFlag(flags)) {
+ // i. Set O.[[Done]] to true.
+ SetDoneFlag(receiver, flags);
+
+ // ii. Return ! CreateIterResultObject(match, false).
+ return AllocateJSIteratorResult(UnsafeCast<JSAny>(match), False);
+ }
+ // a. If global is true,
+ assert(HasGlobalFlag(flags));
+ if (isFastRegExp) {
+ // i. Let matchStr be ? ToString(? Get(match, "0")).
+ const match = UnsafeCast<FastJSRegExpResult>(match);
+ const resultFixedArray = UnsafeCast<FixedArray>(match.elements);
+ const matchStr = UnsafeCast<String>(resultFixedArray.objects[0]);
+
+ // When iterating_regexp is fast, we assume it stays fast even after
+ // accessing the first match from the RegExp result.
+ assert(IsFastRegExpPermissive(iteratingRegExp));
+ const iteratingRegExp = UnsafeCast<JSRegExp>(iteratingRegExp);
+ if (matchStr == kEmptyString) {
+ // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
+ const thisIndex: Smi = FastLoadLastIndex(iteratingRegExp);
+
+ // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
+ // fullUnicode).
+ const nextIndex: Smi = AdvanceStringIndexFast(
+ iteratingString, thisIndex, HasUnicodeFlag(flags));
+
+ // 3. Perform ? Set(R, "lastIndex", nextIndex, true).
+ FastStoreLastIndex(iteratingRegExp, nextIndex);
+ }
+
+ // iii. Return ! CreateIterResultObject(match, false).
+ return AllocateJSIteratorResult(match, False);
+ }
+ assert(!isFastRegExp);
+ // i. Let matchStr be ? ToString(? Get(match, "0")).
+ const match = UnsafeCast<JSAny>(match);
+ const matchStr =
+ ToString_Inline(context, GetProperty(match, SmiConstant(0)));
+
+ if (matchStr == kEmptyString) {
+ // 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).
+ const lastIndex: JSAny = SlowLoadLastIndex(iteratingRegExp);
+ const thisIndex: Number = ToLength_Inline(context, lastIndex);
+
+ // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex,
+ // fullUnicode).
+ const nextIndex: Number = AdvanceStringIndexSlow(
+ iteratingString, thisIndex, HasUnicodeFlag(flags));
+
+ // 3. Perform ? Set(R, "lastIndex", nextIndex, true).
+ SlowStoreLastIndex(iteratingRegExp, nextIndex);
+ }
+ // iii. Return ! CreateIterResultObject(match, false).
+ return AllocateJSIteratorResult(match, False);
+ }
+ // 10. If match is null, then
+ label IfNoMatch {
+ // a. Set O.[[Done]] to true.
+ SetDoneFlag(receiver, flags);
+
+ // b. Return ! CreateIterResultObject(undefined, true).
+ goto ReturnEmptyDoneResult;
+ }
+ }
+ label ReturnEmptyDoneResult {
+ return AllocateJSIteratorResult(Undefined, True);
+ }
+ }
+}