Reland "[builtins] Port RegExpTest to Torque"

This is a reland of f54f92dda1.

Fix IsFastRegExpPermissive to call BranchIfFastRegExp_Permissive.

Original change's description:
> [builtins] Port RegExpTest to Torque
>
> Bug: v8:8976
> Change-Id: Ia4dc120a31eb363599b47b22b749a3146a9c7c73
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1746083
> Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#63211}

Bug: v8:8976, chromium:994041
Change-Id: I86c9c66b060f47164515e29f914b95456c233d30
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1756390
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63255}
This commit is contained in:
Z Nguyen-Huu 2019-08-19 09:03:07 -07:00 committed by Commit Bot
parent 8e065dbe67
commit bc1c36ee56
8 changed files with 80 additions and 99 deletions

View File

@ -994,6 +994,7 @@ torque_files = [
"src/builtins/proxy.tq",
"src/builtins/reflect.tq",
"src/builtins/regexp-replace.tq",
"src/builtins/regexp-test.tq",
"src/builtins/regexp.tq",
"src/builtins/string.tq",
"src/builtins/string-endswith.tq",

View File

@ -865,8 +865,6 @@ namespace internal {
TFJ(RegExpPrototypeSourceGetter, 0, kReceiver) \
/* ES #sec-get-regexp.prototype.sticky */ \
TFJ(RegExpPrototypeStickyGetter, 0, kReceiver) \
/* ES #sec-regexp.prototype.test */ \
TFJ(RegExpPrototypeTest, 1, kReceiver, kString) \
TFS(RegExpPrototypeTestFast, kReceiver, kString) \
CPP(RegExpPrototypeToString) \
/* ES #sec-get-regexp.prototype.unicode */ \

View File

@ -843,8 +843,8 @@ RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
TNode<RegExpMatchInfo>
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<String> string, Label* if_didnotmatch) {
TNode<Context> context, TNode<JSRegExp> maybe_regexp, TNode<String> string,
Label* if_didnotmatch) {
return RegExpPrototypeExecBodyWithoutResult(context, maybe_regexp, string,
if_didnotmatch, true);
}
@ -1052,25 +1052,6 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive(
if_isunmodified, if_ismodified);
}
TNode<BoolT> RegExpBuiltinsAssembler::IsFastRegExp_Permissive(
SloppyTNode<Context> context, SloppyTNode<Object> object) {
Label yup(this), nope(this), out(this);
TVARIABLE(BoolT, var_result);
BranchIfFastRegExp_Permissive(context, CAST(object), &yup, &nope);
BIND(&yup);
var_result = Int32TrueConstant();
Goto(&out);
BIND(&nope);
var_result = Int32FalseConstant();
Goto(&out);
BIND(&out);
return var_result.value();
}
void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* const context,
Node* const object,
Label* if_isunmodified,
@ -1790,9 +1771,9 @@ TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) {
}
// ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
Node* string) {
VARIABLE(var_result, MachineRepresentation::kTagged);
TNode<Object> RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
Node* string) {
TVARIABLE(Object, var_result);
Label out(this);
// Take the slow path of fetching the exec property, calling it, and
@ -1813,12 +1794,11 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
BIND(&if_iscallable);
{
Callable call_callable = CodeFactory::Call(isolate());
Node* const result = CallJS(call_callable, context, exec, regexp, string);
var_result = CAST(CallJS(call_callable, context, exec, regexp, string));
var_result.Bind(result);
GotoIf(IsNull(result), &out);
GotoIf(IsNull(var_result.value()), &out);
ThrowIfNotJSReceiver(context, result,
ThrowIfNotJSReceiver(context, var_result.value(),
MessageTemplate::kInvalidRegExpExecResult, "");
Goto(&out);
@ -1829,9 +1809,8 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
"RegExp.prototype.exec");
Node* const result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow,
context, regexp, string);
var_result.Bind(result);
var_result = CallBuiltin(Builtins::kRegExpPrototypeExecSlow, context,
regexp, string);
Goto(&out);
}
@ -1839,47 +1818,6 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
return var_result.value();
}
// ES#sec-regexp.prototype.test
// RegExp.prototype.test ( S )
TF_BUILTIN(RegExpPrototypeTest, 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.test");
TNode<JSReceiver> receiver = CAST(maybe_receiver);
// Convert {maybe_string} to a String.
TNode<String> string = ToString_Inline(context, maybe_string);
Label fast_path(this), slow_path(this);
BranchIfFastRegExp_Permissive(context, receiver, &fast_path, &slow_path);
BIND(&fast_path);
{
Label if_didnotmatch(this);
RegExpPrototypeExecBodyWithoutResult(context, receiver, string,
&if_didnotmatch, true);
Return(TrueConstant());
BIND(&if_didnotmatch);
Return(FalseConstant());
}
BIND(&slow_path);
{
// Call exec.
TNode<HeapObject> match_indices =
CAST(RegExpExec(context, receiver, string));
// Return true iff exec matched successfully.
Return(SelectBooleanConstant(IsNotNull(match_indices)));
}
}
TF_BUILTIN(RegExpPrototypeTestFast, RegExpBuiltinsAssembler) {
TNode<JSRegExp> regexp = CAST(Parameter(Descriptor::kReceiver));
TNode<String> string = CAST(Parameter(Descriptor::kString));
@ -2179,7 +2117,8 @@ void RegExpMatchAllAssembler::Generate(TNode<Context> context,
// 6. Let matcher be ? Construct(C, « R, flags »).
TNode<String> flags = CAST(FlagsGetter(context, fast_regexp, true));
var_matcher = RegExpCreate(context, native_context, source, flags);
CSA_ASSERT(this, IsFastRegExp_Permissive(context, var_matcher.value()));
CSA_ASSERT(this,
IsFastRegExpPermissive(context, CAST(var_matcher.value())));
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
@ -2336,7 +2275,7 @@ TF_BUILTIN(RegExpMatchFast, RegExpBuiltinsAssembler) {
void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
TNode<Context> context, TNode<JSRegExp> regexp, TNode<String> string) {
CSA_ASSERT(this, IsFastRegExp_Permissive(context, regexp));
CSA_ASSERT(this, IsFastRegExpPermissive(context, regexp));
// Grab the initial value of last index.
TNode<Smi> previous_last_index = FastLoadLastIndex(regexp);
@ -2478,13 +2417,12 @@ TF_BUILTIN(RegExpSearchFast, RegExpBuiltinsAssembler) {
// 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(Node* const context,
Node* const regexp,
void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(TNode<Context> context,
TNode<JSRegExp> regexp,
TNode<String> string,
TNode<Smi> const limit) {
CSA_ASSERT(this, IsFastRegExp_Permissive(context, regexp));
CSA_ASSERT(this,
Word32BinaryNot(FastFlagGetter(CAST(regexp), JSRegExp::kSticky)));
CSA_ASSERT(this, IsFastRegExpPermissive(context, regexp));
CSA_ASSERT(this, Word32BinaryNot(FastFlagGetter(regexp, JSRegExp::kSticky)));
TNode<IntPtrT> const int_limit = SmiUntag(limit);
@ -2606,7 +2544,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
GotoIfNot(SmiEqual(match_to, next_search_from), &next);
GotoIfNot(SmiEqual(match_to, last_matched_until), &next);
Node* const is_unicode = FastFlagGetter(CAST(regexp), JSRegExp::kUnicode);
Node* const is_unicode = FastFlagGetter(regexp, JSRegExp::kUnicode);
Node* const new_next_search_from =
AdvanceStringIndex(string, next_search_from, is_unicode, true);
var_next_search_from = CAST(new_next_search_from);
@ -2698,7 +2636,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
BIND(&out);
{
Node* const result = array.ToJSArray(CAST(context));
Node* const result = array.ToJSArray(context);
Return(result);
}
@ -2898,7 +2836,7 @@ TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
BIND(&if_slow);
{
var_match = CAST(RegExpExec(context, iterating_regexp, iterating_string));
var_match = RegExpExec(context, iterating_regexp, iterating_string);
var_is_fast_regexp = Int32FalseConstant();
Branch(IsNull(var_match.value()), &if_no_match, &if_match);
}
@ -2943,7 +2881,7 @@ TF_BUILTIN(RegExpStringIteratorPrototypeNext, RegExpStringIteratorAssembler) {
// When iterating_regexp is fast, we assume it stays fast even after
// accessing the first match from the RegExp result.
CSA_ASSERT(this, IsFastRegExp_Permissive(context, iterating_regexp));
CSA_ASSERT(this, IsFastRegExpPermissive(context, iterating_regexp));
GotoIfNot(IsEmptyString(match_str), &return_result);
// 1. Let thisIndex be ? ToLength(? Get(R, "lastIndex")).

View File

@ -74,7 +74,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<String> string, Label* if_didnotmatch, const bool is_fastpath);
TNode<RegExpMatchInfo> RegExpPrototypeExecBodyWithoutResultFast(
TNode<Context> context, TNode<JSReceiver> maybe_regexp,
TNode<Context> context, TNode<JSRegExp> maybe_regexp,
TNode<String> string, Label* if_didnotmatch);
TNode<HeapObject> RegExpPrototypeExecBody(TNode<Context> context,
@ -133,10 +133,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Label* if_isunmodified,
Label* if_ismodified);
// Analogous to BranchIfFastRegExp_Permissive, for use in asserts.
TNode<BoolT> IsFastRegExp_Permissive(SloppyTNode<Context> context,
SloppyTNode<Object> object);
// Performs fast path checks on the given object itself, but omits prototype
// checks.
Node* IsFastRegExpNoPrototype(Node* const context, Node* const object);
@ -170,7 +166,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* RegExpInitialize(Node* const context, Node* const regexp,
Node* const maybe_pattern, Node* const maybe_flags);
Node* RegExpExec(Node* context, Node* regexp, Node* string);
TNode<Object> RegExpExec(Node* context, Node* regexp, Node* string);
TNode<Number> AdvanceStringIndex(SloppyTNode<String> string,
SloppyTNode<Number> index,
@ -192,7 +188,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
void RegExpPrototypeSearchBodySlow(Node* const context, Node* const regexp,
Node* const string);
void RegExpPrototypeSplitBody(Node* const context, Node* const regexp,
void RegExpPrototypeSplitBody(TNode<Context> context, TNode<JSRegExp> regexp,
TNode<String> const string,
TNode<Smi> const limit);
};

View File

@ -4,7 +4,7 @@
#include 'src/builtins/builtins-regexp-gen.h'
namespace regexp_replace {
namespace regexp {
extern builtin
StringIndexOf(implicit context: Context)(String, String, Smi): Smi;
@ -23,10 +23,6 @@ namespace regexp_replace {
extern macro
RegExpBuiltinsAssembler::AdvanceStringIndexFast(String, Smi, bool): Smi;
extern macro
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
implicit context: Context)(JSReceiver, String):
RegExpMatchInfo labels IfDidNotMatch;
transitioning macro RegExpReplaceCallableNoExplicitCaptures(implicit context:
Context)(
@ -146,8 +142,9 @@ namespace regexp_replace {
}
while (true) {
const match: RegExpMatchInfo = RegExpPrototypeExecBodyWithoutResultFast(
regexp, string) otherwise break;
const match: RegExpMatchInfo =
regexp::RegExpPrototypeExecBodyWithoutResultFast(regexp, string)
otherwise break;
const matchStart: Smi = match.GetStartOfCapture(0);
const matchEnd: Smi = match.GetEndOfCapture(0);

View File

@ -0,0 +1,26 @@
// 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 {
// ES#sec-regexp.prototype.test
// RegExp.prototype.test ( S )
transitioning javascript builtin RegExpPrototypeTest(
js-implicit context: Context, receiver: Object)(string: String): Object {
const methodName: constexpr string = 'RegExp.prototype.test';
const receiver = Cast<JSReceiver>(receiver)
otherwise ThrowTypeError(kIncompatibleMethodReceiver, methodName);
const str: String = ToString_Inline(context, string);
if (IsFastRegExpPermissive(receiver)) {
RegExpPrototypeExecBodyWithoutResultFast(
UnsafeCast<JSRegExp>(receiver), str)
otherwise return False;
return True;
}
const matchIndices = RegExpExec(context, receiver, str);
return SelectBooleanConstant(matchIndices != Null);
}
}

View File

@ -13,4 +13,20 @@ namespace regexp {
BranchIfFastRegExp_Strict(o) otherwise return true, return false;
}
extern macro RegExpBuiltinsAssembler::BranchIfFastRegExp_Permissive(
implicit context: Context)(HeapObject): never labels IsFast,
IsSlow;
@export
macro IsFastRegExpPermissive(implicit context: Context)(o: HeapObject): bool {
BranchIfFastRegExp_Permissive(o) otherwise return true, return false;
}
extern macro RegExpBuiltinsAssembler::RegExpExec(Context, Object, Object):
Object;
extern macro
RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResultFast(
implicit context: Context)(JSRegExp, String):
RegExpMatchInfo labels IfDidNotMatch;
}

View File

@ -0,0 +1,9 @@
// 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.
v0 = Array().join();
RegExp.prototype.__defineSetter__(0, function() {
})
v24 = v0.search();
assertEquals(v24, 0);