• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include 'src/builtins/builtins-regexp-gen.h'
6
7namespace regexp {
8
9const kATOM: constexpr int31
10    generates 'JSRegExp::ATOM';
11const kTagIndex: constexpr int31
12    generates 'JSRegExp::kTagIndex';
13const kAtomPatternIndex: constexpr int31
14    generates 'JSRegExp::kAtomPatternIndex';
15
16extern transitioning macro RegExpBuiltinsAssembler::FlagGetter(
17    implicit context: Context)(Object, constexpr Flag, constexpr bool): bool;
18
19extern macro UnsafeLoadFixedArrayElement(
20    RegExpMatchInfo, constexpr int31): Object;
21
22transitioning macro RegExpPrototypeMatchBody(implicit context: Context)(
23    regexp: JSReceiver, string: String, isFastPath: constexpr bool): JSAny {
24  if constexpr (isFastPath) {
25    dcheck(Is<FastJSRegExp>(regexp));
26  }
27
28  const isGlobal: bool = FlagGetter(regexp, Flag::kGlobal, isFastPath);
29
30  if (!isGlobal) {
31    return isFastPath ? RegExpPrototypeExecBodyFast(regexp, string) :
32                        RegExpExec(regexp, string);
33  }
34
35  dcheck(isGlobal);
36  const isUnicode: bool = FlagGetter(regexp, Flag::kUnicode, isFastPath);
37
38  StoreLastIndex(regexp, 0, isFastPath);
39
40  // Allocate an array to store the resulting match strings.
41
42  let array = growable_fixed_array::NewGrowableFixedArray();
43
44  // Check if the regexp is an ATOM type. If so, then keep the literal string
45  // to search for so that we can avoid calling substring in the loop below.
46  let atom: bool = false;
47  let searchString: String = EmptyStringConstant();
48  if constexpr (isFastPath) {
49    const maybeAtomRegexp = UnsafeCast<JSRegExp>(regexp);
50    const data = UnsafeCast<FixedArray>(maybeAtomRegexp.data);
51    if (UnsafeCast<Smi>(data.objects[kTagIndex]) == kATOM) {
52      searchString = UnsafeCast<String>(data.objects[kAtomPatternIndex]);
53      atom = true;
54    }
55  }
56
57  while (true) {
58    let match: String = EmptyStringConstant();
59    try {
60      if constexpr (isFastPath) {
61        // On the fast path, grab the matching string from the raw match index
62        // array.
63        const matchIndices: RegExpMatchInfo =
64            RegExpPrototypeExecBodyWithoutResultFast(
65                UnsafeCast<JSRegExp>(regexp), string) otherwise IfDidNotMatch;
66        if (atom) {
67          match = searchString;
68        } else {
69          const matchFrom = UnsafeLoadFixedArrayElement(
70              matchIndices, kRegExpMatchInfoFirstCaptureIndex);
71          const matchTo = UnsafeLoadFixedArrayElement(
72              matchIndices, kRegExpMatchInfoFirstCaptureIndex + 1);
73          match = SubString(
74              string, UnsafeCast<Smi>(matchFrom), UnsafeCast<Smi>(matchTo));
75        }
76      } else {
77        dcheck(!isFastPath);
78        const resultTemp = RegExpExec(regexp, string);
79        if (resultTemp == Null) {
80          goto IfDidNotMatch;
81        }
82        match = ToString_Inline(GetProperty(resultTemp, SmiConstant(0)));
83      }
84      goto IfDidMatch;
85    } label IfDidNotMatch {
86      return array.length == 0 ? Null : array.ToJSArray();
87    } label IfDidMatch {
88      // Store the match, growing the fixed array if needed.
89
90      array.Push(match);
91
92      // Advance last index if the match is the empty string.
93      const matchLength: Smi = match.length_smi;
94      if (matchLength != 0) {
95        continue;
96      }
97      let lastIndex = LoadLastIndex(regexp, isFastPath);
98      if constexpr (isFastPath) {
99        dcheck(TaggedIsPositiveSmi(lastIndex));
100      } else {
101        lastIndex = ToLength_Inline(lastIndex);
102      }
103
104      const newLastIndex: Number = AdvanceStringIndex(
105          string, UnsafeCast<Number>(lastIndex), isUnicode, isFastPath);
106
107      if constexpr (isFastPath) {
108        // On the fast path, we can be certain that lastIndex can never be
109        // incremented to overflow the Smi range since the maximal string
110        // length is less than the maximal Smi value.
111        StaticAssertStringLengthFitsSmi();
112        dcheck(TaggedIsPositiveSmi(newLastIndex));
113      }
114
115      StoreLastIndex(regexp, newLastIndex, isFastPath);
116    }
117  }
118
119  VerifiedUnreachable();
120}
121
122transitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)(
123    receiver: FastJSRegExp, string: String): JSAny {
124  return RegExpPrototypeMatchBody(receiver, string, true);
125}
126
127transitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)(
128    receiver: JSReceiver, string: String): JSAny {
129  return RegExpPrototypeMatchBody(receiver, string, false);
130}
131
132// Helper that skips a few initial checks. and assumes...
133// 1) receiver is a "fast" RegExp
134// 2) pattern is a string
135transitioning builtin RegExpMatchFast(implicit context: Context)(
136    receiver: FastJSRegExp, string: String): JSAny {
137  return FastRegExpPrototypeMatchBody(receiver, string);
138}
139
140// ES#sec-regexp.prototype-@@match
141// RegExp.prototype [ @@match ] ( string )
142transitioning javascript builtin RegExpPrototypeMatch(
143    js-implicit context: NativeContext, receiver: JSAny)(string: JSAny): JSAny {
144  ThrowIfNotJSReceiver(
145      receiver, MessageTemplate::kIncompatibleMethodReceiver,
146      'RegExp.prototype.@@match');
147  const receiver = UnsafeCast<JSReceiver>(receiver);
148  const string: String = ToString_Inline(string);
149
150  // Strict: Reads global and unicode properties.
151  // TODO(jgruber): Handle slow flag accesses on the fast path and make this
152  // permissive.
153  const fastRegExp = Cast<FastJSRegExp>(receiver)
154      otherwise return SlowRegExpPrototypeMatchBody(receiver, string);
155
156  // TODO(pwong): Could be optimized to remove the overhead of calling the
157  //              builtin (at the cost of a larger builtin).
158  return RegExpMatchFast(fastRegExp, string);
159}
160}
161