Commit db61537a authored by jgruber's avatar jgruber Committed by Commit bot

[regexp] Avoid side effects between map load and fast path check

Loading the map, performing a side-effect, and then using the stored
pointer for the fast-path check is another antipattern that can lead to
unintended shapes on the fast path.

BUG=chromium:709029

Review-Url: https://codereview.chromium.org/2807153002
Cr-Commit-Position: refs/heads/master@{#44528}
parent 038bafcb
...@@ -733,16 +733,10 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context, ...@@ -733,16 +733,10 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context, Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context,
Node* const object) { Node* const object) {
return IsFastRegExp(context, object, LoadMap(object));
}
Node* RegExpBuiltinsAssembler::IsFastRegExp(Node* const context,
Node* const object,
Node* const map) {
Label yup(this), nope(this), out(this); Label yup(this), nope(this), out(this);
VARIABLE(var_result, MachineRepresentation::kWord32); VARIABLE(var_result, MachineRepresentation::kWord32);
BranchIfFastRegExp(context, object, map, &yup, &nope); BranchIfFastRegExp(context, object, LoadMap(object), &yup, &nope);
BIND(&yup); BIND(&yup);
var_result.Bind(Int32Constant(1)); var_result.Bind(Int32Constant(1));
...@@ -784,16 +778,16 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { ...@@ -784,16 +778,16 @@ TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
// Ensure {maybe_receiver} is a JSRegExp. // Ensure {maybe_receiver} is a JSRegExp.
Node* const regexp_map = ThrowIfNotInstanceType( ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); "RegExp.prototype.exec");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
Label if_isfastpath(this), if_isslowpath(this); Label if_isfastpath(this), if_isslowpath(this);
Branch(IsFastRegExpNoPrototype(context, receiver, regexp_map), &if_isfastpath, Branch(IsFastRegExpNoPrototype(context, receiver, LoadMap(receiver)),
&if_isslowpath); &if_isfastpath, &if_isslowpath);
BIND(&if_isfastpath); BIND(&if_isfastpath);
{ {
...@@ -1498,16 +1492,17 @@ TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { ...@@ -1498,16 +1492,17 @@ TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( ThrowIfNotJSReceiver(context, maybe_receiver,
context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.test"); "RegExp.prototype.test");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path,
&slow_path);
BIND(&fast_path); BIND(&fast_path);
{ {
...@@ -1908,16 +1903,17 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { ...@@ -1908,16 +1903,17 @@ TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( ThrowIfNotJSReceiver(context, maybe_receiver,
context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@match"); "RegExp.prototype.@@match");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path,
&slow_path);
BIND(&fast_path); BIND(&fast_path);
RegExpPrototypeMatchBody(context, receiver, string, true); RegExpPrototypeMatchBody(context, receiver, string, true);
...@@ -2036,16 +2032,17 @@ TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) { ...@@ -2036,16 +2032,17 @@ TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( ThrowIfNotJSReceiver(context, maybe_receiver,
context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@search"); "RegExp.prototype.@@search");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
Label fast_path(this), slow_path(this); Label fast_path(this), slow_path(this);
BranchIfFastRegExp(context, receiver, map, &fast_path, &slow_path); BranchIfFastRegExp(context, receiver, LoadMap(receiver), &fast_path,
&slow_path);
BIND(&fast_path); BIND(&fast_path);
RegExpPrototypeSearchBodyFast(context, receiver, string); RegExpPrototypeSearchBodyFast(context, receiver, string);
...@@ -2373,16 +2370,16 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { ...@@ -2373,16 +2370,16 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( ThrowIfNotJSReceiver(context, maybe_receiver,
context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@split"); "RegExp.prototype.@@split");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string); Node* const string = ToString(context, maybe_string);
Label stub(this), runtime(this, Label::kDeferred); Label stub(this), runtime(this, Label::kDeferred);
BranchIfFastRegExp(context, receiver, map, &stub, &runtime); BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime);
BIND(&stub); BIND(&stub);
Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string, Return(CallBuiltin(Builtins::kRegExpSplit, context, receiver, string,
...@@ -2804,9 +2801,9 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { ...@@ -2804,9 +2801,9 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
// } // }
// Ensure {maybe_receiver} is a JSReceiver. // Ensure {maybe_receiver} is a JSReceiver.
Node* const map = ThrowIfNotJSReceiver( ThrowIfNotJSReceiver(context, maybe_receiver,
context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, MessageTemplate::kIncompatibleMethodReceiver,
"RegExp.prototype.@@replace"); "RegExp.prototype.@@replace");
Node* const receiver = maybe_receiver; Node* const receiver = maybe_receiver;
// Convert {maybe_string} to a String. // Convert {maybe_string} to a String.
...@@ -2814,7 +2811,7 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { ...@@ -2814,7 +2811,7 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
// Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
Label stub(this), runtime(this, Label::kDeferred); Label stub(this), runtime(this, Label::kDeferred);
BranchIfFastRegExp(context, receiver, map, &stub, &runtime); BranchIfFastRegExp(context, receiver, LoadMap(receiver), &stub, &runtime);
BIND(&stub); BIND(&stub);
Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string, Return(CallBuiltin(Builtins::kRegExpReplace, context, receiver, string,
......
...@@ -59,7 +59,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler { ...@@ -59,7 +59,6 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
// Analogous to BranchIfFastRegExp, for use in asserts. // Analogous to BranchIfFastRegExp, for use in asserts.
Node* IsFastRegExp(Node* const context, Node* const object); Node* IsFastRegExp(Node* const context, Node* const object);
Node* IsFastRegExp(Node* const context, Node* const object, Node* const map);
// Performs fast path checks on the given object itself, but omits prototype // Performs fast path checks on the given object itself, but omits prototype
// checks. // checks.
......
// Copyright 2017 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.
// Changes the map of obj.
function mutateObjectOnStringConversion(obj) {
return { toString: () => { obj.x = 42;return "";}};
}
{
const re = /./;
re.exec(mutateObjectOnStringConversion(re));
}
{
const re = /./;
re.test(mutateObjectOnStringConversion(re));
}
{
const re = /./;
re[Symbol.match](mutateObjectOnStringConversion(re));
}
{
const re = /./;
re[Symbol.search](mutateObjectOnStringConversion(re));
}
{
const re = /./;
re[Symbol.split](mutateObjectOnStringConversion(re));
}
{
const re = /./;
re[Symbol.replace](mutateObjectOnStringConversion(re));
}
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