Commit fa636ac3 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

[builtins] Port Regexp search to Torque

Bug: v8:8976
Change-Id: I281dc72dcdf03a1d05fdc632c9e9228d62bd85b8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1783099
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63656}
parent 4ae9075b
......@@ -996,6 +996,7 @@ torque_files = [
"src/builtins/reflect.tq",
"src/builtins/regexp-match.tq",
"src/builtins/regexp-replace.tq",
"src/builtins/regexp-search.tq",
"src/builtins/regexp-source.tq",
"src/builtins/regexp-test.tq",
"src/builtins/regexp.tq",
......
......@@ -1478,6 +1478,8 @@ extern class JSRegExpResultIndices extends JSArray {
groups: JSAny;
}
transient type FastJSRegExpResult extends JSRegExpResult;
@generateCppClass
extern class JSRegExpStringIterator extends JSObject {
// The [[IteratingRegExp]] internal property.
......@@ -2388,6 +2390,13 @@ Cast<JSRegExp>(o: HeapObject): JSRegExp
goto CastError;
}
Cast<FastJSRegExpResult>(implicit context: Context)(o: HeapObject):
FastJSRegExpResult
labels CastError {
if (regexp::IsFastRegExpResult(o)) return %RawDownCast<FastJSRegExpResult>(o);
goto CastError;
}
Cast<Map>(implicit context: Context)(o: HeapObject): Map
labels CastError {
if (IsMap(o)) return %RawDownCast<Map>(o);
......
......@@ -851,8 +851,6 @@ namespace internal {
TFJ(RegExpPrototypeExec, 1, kReceiver, kString) \
/* https://tc39.github.io/proposal-string-matchall/ */ \
TFJ(RegExpPrototypeMatchAll, 1, kReceiver, kString) \
/* ES #sec-regexp.prototype-@@search */ \
TFJ(RegExpPrototypeSearch, 1, kReceiver, kString) \
CPP(RegExpPrototypeToString) \
CPP(RegExpRightContextGetter) \
\
......@@ -863,7 +861,6 @@ namespace internal {
TFS(RegExpExecInternal, kRegExp, kString, kLastIndex, kMatchInfo) \
ASM(RegExpInterpreterTrampoline, CCall) \
TFS(RegExpPrototypeExecSlow, kReceiver, kString) \
TFS(RegExpSearchFast, kReceiver, kPattern) \
TFS(RegExpSplit, kRegExp, kString, kLimit) \
\
/* RegExp String Iterator */ \
......
......@@ -2041,148 +2041,6 @@ TF_BUILTIN(RegExpPrototypeMatchAll, RegExpMatchAllAssembler) {
Generate(context, native_context, receiver, maybe_string);
}
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string) {
CSA_ASSERT(this, IsFastRegExpPermissive(context, regexp));
// Grab the initial value of last index.
TNode<Smi> previous_last_index = FastLoadLastIndex(regexp);
// Ensure last index is 0.
FastStoreLastIndex(regexp, SmiZero());
// Call exec.
Label if_didnotmatch(this);
TNode<RegExpMatchInfo> match_indices = RegExpPrototypeExecBodyWithoutResult(
context, regexp, string, &if_didnotmatch, true);
// Successful match.
{
// Reset last index.
FastStoreLastIndex(regexp, previous_last_index);
// Return the index of the match.
TNode<Object> const index = LoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex);
Return(index);
}
BIND(&if_didnotmatch);
{
// Reset last index and return -1.
FastStoreLastIndex(regexp, previous_last_index);
Return(SmiConstant(-1));
}
}
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
TNode<Context> context, Node* const regexp, Node* const string) {
CSA_ASSERT(this, IsJSReceiver(regexp));
CSA_ASSERT(this, IsString(string));
Isolate* const isolate = this->isolate();
TNode<Smi> const smi_zero = SmiZero();
// Grab the initial value of last index.
TNode<Object> const previous_last_index =
SlowLoadLastIndex(context, CAST(regexp));
// Ensure last index is 0.
{
Label next(this), slow(this, Label::kDeferred);
BranchIfSameValue(previous_last_index, smi_zero, &next, &slow);
BIND(&slow);
SlowStoreLastIndex(context, regexp, smi_zero);
Goto(&next);
BIND(&next);
}
// Call exec.
TNode<Object> const exec_result = RegExpExec(context, regexp, string);
// Reset last index if necessary.
{
Label next(this), slow(this, Label::kDeferred);
TNode<Object> const current_last_index =
SlowLoadLastIndex(context, CAST(regexp));
BranchIfSameValue(current_last_index, previous_last_index, &next, &slow);
BIND(&slow);
SlowStoreLastIndex(context, regexp, previous_last_index);
Goto(&next);
BIND(&next);
}
// Return -1 if no match was found.
{
Label next(this);
GotoIfNot(IsNull(exec_result), &next);
Return(SmiConstant(-1));
BIND(&next);
}
// Return the index of the match.
{
Label fast_result(this), slow_result(this, Label::kDeferred);
BranchIfFastRegExpResult(context, exec_result, &fast_result, &slow_result);
BIND(&fast_result);
{
TNode<Object> const index =
LoadObjectField(CAST(exec_result), JSRegExpResult::kIndexOffset);
Return(index);
}
BIND(&slow_result);
{
Return(GetProperty(context, exec_result,
isolate->factory()->index_string()));
}
}
}
// ES#sec-regexp.prototype-@@search
// RegExp.prototype [ @@search ] ( string )
TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
TNode<Object> maybe_receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> maybe_string = CAST(Parameter(Descriptor::kString));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// Ensure {maybe_receiver} is a JSReceiver.
ThrowIfNotJSReceiver(context, maybe_receiver,
MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@search");
TNode<JSReceiver> receiver = CAST(maybe_receiver);
// Convert {maybe_string} to a String.
TNode<String> const string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this);
BranchIfFastRegExp_Permissive(context, receiver, &fast_path, &slow_path);
BIND(&fast_path);
// TODO(pwong): Could be optimized to remove the overhead of calling the
// builtin (at the cost of a larger builtin).
Return(CallBuiltin(Builtins::kRegExpSearchFast, context, receiver, string));
BIND(&slow_path);
RegExpPrototypeSearchBodySlow(context, receiver, string);
}
// Helper that skips a few initial checks. and assumes...
// 1) receiver is a "fast" RegExp
// 2) pattern is a string
TF_BUILTIN(RegExpSearchFast, RegExpBuiltinsAssembler) {
TNode<JSRegExp> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<String> string = CAST(Parameter(Descriptor::kPattern));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
RegExpPrototypeSearchBodyFast(context, receiver, string);
}
// Generates the fast path for @@split. {regexp} is an unmodified, non-sticky
// JSRegExp, {string} is a String, and {limit} is a Smi.
void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(TNode<Context> context,
......
......@@ -185,12 +185,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<String> const string,
const bool is_fastpath);
void RegExpPrototypeSearchBodyFast(TNode<Context> context,
TNode<JSRegExp> regexp,
TNode<String> string);
void RegExpPrototypeSearchBodySlow(TNode<Context> context, Node* const regexp,
Node* const string);
void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp,
TNode<String> const string,
TNode<Smi> const limit);
......
// 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 macro RegExpBuiltinsAssembler::FastLoadLastIndex(JSRegExp): Smi;
extern macro RegExpBuiltinsAssembler::FastStoreLastIndex(JSRegExp, Smi): void;
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 transitioning macro RegExpBuiltinsAssembler::SlowLoadLastIndex(
implicit context: Context)(JSAny): JSAny;
extern transitioning macro RegExpBuiltinsAssembler::SlowStoreLastIndex(
implicit context: Context)(JSAny, JSAny): void;
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.
const execResult = RegExpExec(context, regexp, string);
// 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);
}
}
......@@ -22,8 +22,8 @@ namespace regexp {
BranchIfFastRegExp_Permissive(o) otherwise return true, return false;
}
extern macro RegExpBuiltinsAssembler::RegExpExec(Context, Object, Object):
Object;
extern macro RegExpBuiltinsAssembler::RegExpExec(Context, JSAny, JSAny):
JSAny;
extern macro
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment