Commit a0858cf0 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[regexp] Add use counters for IsRegExp

A spec change to simplify IsRegExp has been proposed:

https://github.com/tc39/ecma262/pull/1318

This CL adds use counters for cases in which the spec change would
alter behavior:

1. o[@@match] is trueish but o is not a JSRegExp
2. o[@@match] is falseish (but not undefined) and o is a JSRegExp

This is the V8 side of required changes.
The Chromium-side CL: https://crrev.com/c/1360730

Drive-by: TNodeify IsRegExp.

Tbr: yangguo@chromium.org
Bug: v8:8522
Change-Id: I3766e02977f256a80d0e59472d3bafa9c692af9e
Reviewed-on: https://chromium-review.googlesource.com/c/1360630Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarMathias Bynens <mathias@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58064}
parent 8c7a29b2
...@@ -7320,6 +7320,8 @@ class V8_EXPORT Isolate { ...@@ -7320,6 +7320,8 @@ class V8_EXPORT Isolate {
kAttemptOverrideReadOnlyOnPrototypeSloppy = 69, kAttemptOverrideReadOnlyOnPrototypeSloppy = 69,
kAttemptOverrideReadOnlyOnPrototypeStrict = 70, kAttemptOverrideReadOnlyOnPrototypeStrict = 70,
kOptimizedFunctionWithOneShotBytecode = 71, kOptimizedFunctionWithOneShotBytecode = 71,
kRegExpMatchIsTrueishOnNonJSRegExp = 72,
kRegExpMatchIsFalseishOnJSRegExp = 73,
// If you add new values here, you'll also need to update Chromium's: // If you add new values here, you'll also need to update Chromium's:
// web_feature.mojom, UseCounterCallback.cpp, and enums.xml. V8 changes to // web_feature.mojom, UseCounterCallback.cpp, and enums.xml. V8 changes to
......
...@@ -1202,20 +1202,20 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context, ...@@ -1202,20 +1202,20 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
} }
// ES#sec-isregexp IsRegExp ( argument ) // ES#sec-isregexp IsRegExp ( argument )
Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, TNode<BoolT> RegExpBuiltinsAssembler::IsRegExp(TNode<Context> context,
Node* const maybe_receiver) { TNode<Object> maybe_receiver) {
Label out(this), if_isregexp(this); Label out(this), if_isregexp(this);
VARIABLE(var_result, MachineRepresentation::kWord32, Int32Constant(0)); TVARIABLE(BoolT, var_result, Int32FalseConstant());
GotoIf(TaggedIsSmi(maybe_receiver), &out); GotoIf(TaggedIsSmi(maybe_receiver), &out);
GotoIfNot(IsJSReceiver(maybe_receiver), &out); GotoIfNot(IsJSReceiver(CAST(maybe_receiver)), &out);
Node* const receiver = maybe_receiver; TNode<JSReceiver> receiver = CAST(maybe_receiver);
// Check @@match. // Check @@match.
{ {
Node* const value = TNode<Object> value =
GetProperty(context, receiver, isolate()->factory()->match_symbol()); GetProperty(context, receiver, isolate()->factory()->match_symbol());
Label match_isundefined(this), match_isnotundefined(this); Label match_isundefined(this), match_isnotundefined(this);
...@@ -1225,11 +1225,26 @@ Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context, ...@@ -1225,11 +1225,26 @@ Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context,
Branch(IsJSRegExp(receiver), &if_isregexp, &out); Branch(IsJSRegExp(receiver), &if_isregexp, &out);
BIND(&match_isnotundefined); BIND(&match_isnotundefined);
BranchIfToBooleanIsTrue(value, &if_isregexp, &out); Label match_istrueish(this), match_isfalseish(this);
BranchIfToBooleanIsTrue(value, &match_istrueish, &match_isfalseish);
// The common path. Symbol.match exists, equals the RegExpPrototypeMatch
// function (and is thus trueish), and the receiver is a JSRegExp.
BIND(&match_istrueish);
GotoIf(IsJSRegExp(receiver), &if_isregexp);
CallRuntime(Runtime::kIncrementUseCounter, context,
SmiConstant(v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp));
Goto(&if_isregexp);
BIND(&match_isfalseish);
GotoIfNot(IsJSRegExp(receiver), &out);
CallRuntime(Runtime::kIncrementUseCounter, context,
SmiConstant(v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp));
Goto(&out);
} }
BIND(&if_isregexp); BIND(&if_isregexp);
var_result.Bind(Int32Constant(1)); var_result = Int32TrueConstant();
Goto(&out); Goto(&out);
BIND(&out); BIND(&out);
...@@ -1299,7 +1314,7 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) { ...@@ -1299,7 +1314,7 @@ TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
Node* const regexp_function = Node* const regexp_function =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
Node* const pattern_is_regexp = IsRegExp(context, pattern); TNode<BoolT> pattern_is_regexp = IsRegExp(context, pattern);
{ {
Label next(this); Label next(this);
......
...@@ -112,7 +112,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -112,7 +112,7 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
void FlagGetter(Node* context, Node* receiver, JSRegExp::Flag flag, void FlagGetter(Node* context, Node* receiver, JSRegExp::Flag flag,
int counter, const char* method_name); int counter, const char* method_name);
Node* IsRegExp(Node* const context, Node* const maybe_receiver); TNode<BoolT> IsRegExp(TNode<Context> context, TNode<Object> maybe_receiver);
Node* RegExpInitialize(Node* const context, Node* const regexp, Node* RegExpInitialize(Node* const context, Node* const regexp,
Node* const maybe_pattern, Node* const maybe_flags); Node* const maybe_pattern, Node* const maybe_flags);
......
...@@ -131,7 +131,18 @@ Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) { ...@@ -131,7 +131,18 @@ Maybe<bool> RegExpUtils::IsRegExp(Isolate* isolate, Handle<Object> object) {
isolate->factory()->match_symbol()), isolate->factory()->match_symbol()),
Nothing<bool>()); Nothing<bool>());
if (!match->IsUndefined(isolate)) return Just(match->BooleanValue(isolate)); if (!match->IsUndefined(isolate)) {
const bool match_as_boolean = match->BooleanValue(isolate);
if (match_as_boolean && !object->IsJSRegExp()) {
isolate->CountUsage(v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp);
} else if (!match_as_boolean && object->IsJSRegExp()) {
isolate->CountUsage(v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp);
}
return Just(match_as_boolean);
}
return Just(object->IsJSRegExp()); return Just(object->IsJSRegExp());
} }
......
...@@ -165,6 +165,40 @@ TEST(OverrideReadOnlyPropertyOnPrototype) { ...@@ -165,6 +165,40 @@ TEST(OverrideReadOnlyPropertyOnPrototype) {
} }
} }
TEST(RegExpMatchIsTrueishOnNonJSRegExp) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
LocalContext env;
int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
global_use_counts = use_counts;
CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
CompileRun("new RegExp(/./); new RegExp('');");
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp]);
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp]);
CompileRun("let p = { [Symbol.match]: true }; new RegExp(p);");
CHECK_EQ(1, use_counts[v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp]);
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp]);
}
TEST(RegExpMatchIsFalseishOnJSRegExp) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
LocalContext env;
int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
global_use_counts = use_counts;
CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
CompileRun("new RegExp(/./); new RegExp('');");
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp]);
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp]);
CompileRun("let p = /./; p[Symbol.match] = false; new RegExp(p);");
CHECK_EQ(0, use_counts[v8::Isolate::kRegExpMatchIsTrueishOnNonJSRegExp]);
CHECK_EQ(1, use_counts[v8::Isolate::kRegExpMatchIsFalseishOnJSRegExp]);
}
} // namespace test_usecounters } // namespace test_usecounters
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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