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

[builtins] Port RegexpPrototypeMatchBody to Torque

Bug: v8:8976
Change-Id: Ifa9b874b5b75b51046ba611db2b9fad3cbd33905
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1920066
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65055}
parent c5f10123
......@@ -1346,165 +1346,6 @@ TNode<Number> RegExpBuiltinsAssembler::AdvanceStringIndex(
return var_result.value();
}
TNode<Object> RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
TNode<Context> context, TNode<Object> regexp, TNode<String> string,
const bool is_fastpath) {
if (is_fastpath) {
CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
BranchIfFastRegExp_Strict(context, CAST(regexp), ok, not_ok);
});
}
TVARIABLE(Object, var_result);
const TNode<BoolT> is_global =
FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath);
Label if_isglobal(this), if_isnotglobal(this), done(this);
Branch(is_global, &if_isglobal, &if_isnotglobal);
BIND(&if_isnotglobal);
{
var_result =
is_fastpath ? RegExpPrototypeExecBodyFast(context, CAST(regexp), string)
: RegExpExec(context, CAST(regexp), string);
Goto(&done);
}
BIND(&if_isglobal);
{
const TNode<BoolT> is_unicode =
FlagGetter(context, regexp, JSRegExp::kUnicode, is_fastpath);
StoreLastIndex(context, regexp, SmiZero(), is_fastpath);
// Allocate an array to store the resulting match strings.
GrowableFixedArray array(state());
// Loop preparations. Within the loop, collect results from RegExpExec
// and store match strings in the array.
Label loop(this,
{array.var_array(), array.var_length(), array.var_capacity()}),
out(this);
// Check if the regexp is an ATOM type. If then, keep the literal string to
// search for so that we can avoid calling substring in the loop below.
TVARIABLE(BoolT, var_atom, Int32FalseConstant());
TVARIABLE(String, var_search_string, EmptyStringConstant());
if (is_fastpath) {
TNode<JSRegExp> maybe_atom_regexp = CAST(regexp);
TNode<FixedArray> data =
CAST(LoadObjectField(maybe_atom_regexp, JSRegExp::kDataOffset));
GotoIfNot(SmiEqual(CAST(LoadFixedArrayElement(data, JSRegExp::kTagIndex)),
SmiConstant(JSRegExp::ATOM)),
&loop);
var_search_string =
CAST(LoadFixedArrayElement(data, JSRegExp::kAtomPatternIndex));
var_atom = Int32TrueConstant();
}
Goto(&loop);
BIND(&loop);
{
TVARIABLE(String, var_match);
Label if_didmatch(this), if_didnotmatch(this);
if (is_fastpath) {
// On the fast path, grab the matching string from the raw match index
// array.
TNode<RegExpMatchInfo> match_indices =
RegExpPrototypeExecBodyWithoutResultFast(context, CAST(regexp),
string, &if_didnotmatch);
Label dosubstring(this), donotsubstring(this);
Branch(var_atom.value(), &donotsubstring, &dosubstring);
BIND(&dosubstring);
{
const TNode<Object> match_from = UnsafeLoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex);
const TNode<Object> match_to = UnsafeLoadFixedArrayElement(
match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
var_match = CAST(CallBuiltin(Builtins::kSubString, context, string,
match_from, match_to));
Goto(&if_didmatch);
}
BIND(&donotsubstring);
var_match = var_search_string.value();
Goto(&if_didmatch);
} else {
DCHECK(!is_fastpath);
const TNode<Object> result = RegExpExec(context, CAST(regexp), string);
Label load_match(this);
Branch(IsNull(result), &if_didnotmatch, &load_match);
BIND(&load_match);
var_match =
ToString_Inline(context, GetProperty(context, result, SmiZero()));
Goto(&if_didmatch);
}
BIND(&if_didnotmatch);
{
// Return null if there were no matches, otherwise just exit the loop.
GotoIfNot(IntPtrEqual(array.length(), IntPtrZero()), &out);
var_result = NullConstant();
Goto(&done);
}
BIND(&if_didmatch);
{
TNode<String> match = var_match.value();
// Store the match, growing the fixed array if needed.
array.Push(match);
// Advance last index if the match is the empty string.
const TNode<Smi> match_length = LoadStringLengthAsSmi(match);
GotoIfNot(SmiEqual(match_length, SmiZero()), &loop);
TNode<Object> last_index = LoadLastIndex(context, regexp, is_fastpath);
if (is_fastpath) {
CSA_ASSERT(this, TaggedIsPositiveSmi(last_index));
} else {
last_index = ToLength_Inline(context, last_index);
}
TNode<Number> new_last_index = AdvanceStringIndex(
string, CAST(last_index), is_unicode, is_fastpath);
if (is_fastpath) {
// On the fast path, we can be certain that lastIndex can never be
// incremented to overflow the Smi range since the maximal string
// length is less than the maximal Smi value.
STATIC_ASSERT(String::kMaxLength < Smi::kMaxValue);
CSA_ASSERT(this, TaggedIsPositiveSmi(new_last_index));
}
StoreLastIndex(context, regexp, new_last_index, is_fastpath);
Goto(&loop);
}
}
BIND(&out);
{
// Wrap the match in a JSArray.
var_result = array.ToJSArray(context);
Goto(&done);
}
}
BIND(&done);
return var_result.value();
}
// ES#sec-createregexpstringiterator
// CreateRegExpStringIterator ( R, S, global, fullUnicode )
TNode<Object> RegExpMatchAllAssembler::CreateRegExpStringIterator(
......
......@@ -159,11 +159,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
return CAST(AdvanceStringIndex(string, index, is_unicode, false));
}
TNode<Object> RegExpPrototypeMatchBody(TNode<Context> context,
TNode<Object> regexp,
const TNode<String> string,
const bool is_fastpath);
TNode<JSArray> RegExpPrototypeSplitBody(TNode<Context> context,
TNode<JSRegExp> regexp,
const TNode<String> string,
......
......@@ -6,8 +6,116 @@
namespace regexp {
extern transitioning macro RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(
implicit context: Context)(Object, String, constexpr bool): JSAny;
const kATOM: constexpr int31
generates 'JSRegExp::ATOM';
const kTagIndex: constexpr int31
generates 'JSRegExp::kTagIndex';
const kAtomPatternIndex: constexpr int31
generates 'JSRegExp::kAtomPatternIndex';
extern transitioning macro RegExpBuiltinsAssembler::FlagGetter(
implicit context: Context)(Object, constexpr Flag, constexpr bool): bool;
transitioning macro RegExpPrototypeMatchBody(implicit context: Context)(
regexp: JSReceiver, string: String, isFastPath: constexpr bool): JSAny {
if constexpr (isFastPath) {
assert(Is<FastJSRegExp>(regexp));
}
const isGlobal: bool = FlagGetter(regexp, kGlobal, isFastPath);
if (!isGlobal) {
return isFastPath ? RegExpPrototypeExecBodyFast(regexp, string) :
RegExpExec(regexp, string);
}
assert(isGlobal);
const isUnicode: bool = FlagGetter(regexp, kUnicode, isFastPath);
StoreLastIndex(regexp, 0, isFastPath);
// Allocate an array to store the resulting match strings.
let array = growable_fixed_array::NewGrowableFixedArray();
// Check if the regexp is an ATOM type. If so, then keep the literal string
// to search for so that we can avoid calling substring in the loop below.
let atom: bool = false;
let searchString: String = EmptyStringConstant();
if constexpr (isFastPath) {
const maybeAtomRegexp = UnsafeCast<JSRegExp>(regexp);
const data = UnsafeCast<FixedArray>(maybeAtomRegexp.data);
if (UnsafeCast<Smi>(data.objects[kTagIndex]) == kATOM) {
searchString = UnsafeCast<String>(data.objects[kAtomPatternIndex]);
atom = true;
}
}
while (true) {
let match: String = EmptyStringConstant();
try {
if constexpr (isFastPath) {
// On the fast path, grab the matching string from the raw match index
// array.
const matchIndices: RegExpMatchInfo =
RegExpPrototypeExecBodyWithoutResultFast(
UnsafeCast<JSRegExp>(regexp), string) otherwise IfDidNotMatch;
if (atom) {
match = searchString;
} else {
const matchFrom: Smi = matchIndices.GetStartOfCapture(0);
const matchTo: Smi = matchIndices.GetEndOfCapture(0);
match = SubString(string, matchFrom, matchTo);
}
} else {
assert(!isFastPath);
const resultTemp = RegExpExec(regexp, string);
if (resultTemp == Null) {
goto IfDidNotMatch;
}
match = ToString_Inline(GetProperty(resultTemp, SmiConstant(0)));
}
goto IfDidMatch;
}
label IfDidNotMatch {
return array.length == 0 ? Null : array.ToJSArray();
}
label IfDidMatch {
// Store the match, growing the fixed array if needed.
array.Push(match);
// Advance last index if the match is the empty string.
const matchLength: Smi = match.length_smi;
if (matchLength != 0) {
continue;
}
let lastIndex = LoadLastIndex(regexp, isFastPath);
if constexpr (isFastPath) {
assert(TaggedIsPositiveSmi(lastIndex));
} else {
lastIndex = ToLength_Inline(lastIndex);
}
const newLastIndex: Number = AdvanceStringIndex(
string, UnsafeCast<Number>(lastIndex), isUnicode, isFastPath);
if constexpr (isFastPath) {
// On the fast path, we can be certain that lastIndex can never be
// incremented to overflow the Smi range since the maximal string
// length is less than the maximal Smi value.
const kMaxStringLengthFitsSmi: constexpr bool =
kStringMaxLengthUintptr < kSmiMaxValue;
StaticAssert(kMaxStringLengthFitsSmi);
assert(TaggedIsPositiveSmi(newLastIndex));
}
StoreLastIndex(regexp, newLastIndex, isFastPath);
}
}
VerifiedUnreachable();
}
transitioning macro FastRegExpPrototypeMatchBody(implicit context: Context)(
receiver: FastJSRegExp, string: String): JSAny {
......@@ -15,7 +123,7 @@ namespace regexp {
}
transitioning macro SlowRegExpPrototypeMatchBody(implicit context: Context)(
receiver: Object, string: String): JSAny {
receiver: JSReceiver, string: String): JSAny {
return RegExpPrototypeMatchBody(receiver, string, false);
}
......
......@@ -341,6 +341,8 @@ namespace regexp {
extern builtin
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
extern macro RegExpBuiltinsAssembler::AdvanceStringIndex(
String, Number, bool, constexpr bool): Number;
extern macro
RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi;
extern macro
......
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