regexp-search.tq 3.48 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
// 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 {

  transitioning macro
  RegExpPrototypeSearchBodyFast(implicit context: Context)(
      regexp: JSRegExp, string: String): JSAny {
    assert(IsFastRegExpPermissive(regexp));

    // Grab the initial value of last index.
    const previousLastIndex: Smi = FastLoadLastIndex(regexp);

    // Ensure last index is 0.
    FastStoreLastIndex(regexp, 0);

    // Call exec.
    try {
      const matchIndices: RegExpMatchInfo =
          RegExpPrototypeExecBodyWithoutResultFast(regexp, string)
          otherwise DidNotMatch;

      // Successful match.
      // Reset last index.
      FastStoreLastIndex(regexp, previousLastIndex);

      // Return the index of the match.
      return UnsafeCast<Smi>(
          matchIndices.objects[kRegExpMatchInfoFirstCaptureIndex]);
    }
    label DidNotMatch {
      // Reset last index and return -1.
      FastStoreLastIndex(regexp, previousLastIndex);
      return SmiConstant(-1);
    }
  }

  extern macro RegExpBuiltinsAssembler::BranchIfFastRegExpResult(
      implicit context: Context)(Object): never labels IsUnmodified,
      IsModified;

  macro
  IsFastRegExpResult(implicit context: Context)(execResult: HeapObject): bool {
    BranchIfFastRegExpResult(execResult) otherwise return true, return false;
  }

  transitioning macro RegExpPrototypeSearchBodySlow(implicit context: Context)(
      regexp: JSReceiver, string: String): JSAny {
    // Grab the initial value of last index.
    const previousLastIndex = SlowLoadLastIndex(regexp);
    const smiZero: Smi = 0;

    // Ensure last index is 0.
    if (!SameValue(previousLastIndex, smiZero)) {
      SlowStoreLastIndex(regexp, smiZero);
    }

    // Call exec.
62
    const execResult = RegExpExec(regexp, string);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

    // Reset last index if necessary.
    const currentLastIndex = SlowLoadLastIndex(regexp);
    if (!SameValue(currentLastIndex, previousLastIndex)) {
      SlowStoreLastIndex(regexp, previousLastIndex);
    }

    // Return -1 if no match was found.
    if (execResult == Null) {
      return SmiConstant(-1);
    }

    // Return the index of the match.
    const fastExecResult = Cast<FastJSRegExpResult>(execResult)
        otherwise return GetProperty(execResult, 'index');
    return fastExecResult.index;
  }

  // Helper that skips a few initial checks. and assumes...
  // 1) receiver is a "fast permissive" RegExp
  // 2) pattern is a string
  transitioning builtin RegExpSearchFast(implicit context: Context)(
      receiver: JSRegExp, string: String): JSAny {
    return RegExpPrototypeSearchBodyFast(receiver, string);
  }

  // ES#sec-regexp.prototype-@@search
  // RegExp.prototype [ @@search ] ( string )
  transitioning javascript builtin RegExpPrototypeSearch(
      js-implicit context: Context, receiver: JSAny)(string: JSAny): JSAny {
    ThrowIfNotJSReceiver(
        receiver, kIncompatibleMethodReceiver, 'RegExp.prototype.@@search');
    const receiver = UnsafeCast<JSReceiver>(receiver);
    const string: String = ToString_Inline(context, string);

    if (IsFastRegExpPermissive(receiver)) {
      // TODO(pwong): Could be optimized to remove the overhead of calling the
      //              builtin (at the cost of a larger builtin).
      return RegExpSearchFast(UnsafeCast<JSRegExp>(receiver), string);
    }
    return RegExpPrototypeSearchBodySlow(receiver, string);
  }
}