Commit acadb202 authored by Ujjwal Sharma's avatar Ujjwal Sharma Committed by Commit Bot

[turbofan] add fast path for String.p.startsWith

Add a fast path for String.p.startsWith(str) when length of str is 1.

Bug: v8:8400
Change-Id: I65e657549902dc3ad064a213d815dd098ce6455f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1491872
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60091}
parent 96e40682
......@@ -3623,6 +3623,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceStringPrototypeIndexOf(node);
case Builtins::kStringPrototypeCharAt:
return ReduceStringPrototypeCharAt(node);
case Builtins::kStringPrototypeStartsWith:
return ReduceStringPrototypeStartsWith(node);
case Builtins::kStringPrototypeCharCodeAt:
return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(),
node);
......@@ -5160,6 +5162,78 @@ Reduction JSCallReducer::ReduceStringPrototypeStringAt(
return Replace(value);
}
// ES section 21.1.3.20
// String.prototype.startsWith ( searchString [ , position ] )
Reduction JSCallReducer::ReduceStringPrototypeStartsWith(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* string = NodeProperties::GetValueInput(node, 1);
Node* search_string = NodeProperties::GetValueInput(node, 2);
Node* position = node->op()->ValueInputCount() >= 4
? NodeProperties::GetValueInput(node, 3)
: jsgraph()->ZeroConstant();
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
HeapObjectMatcher m(search_string);
if (m.HasValue()) {
ObjectRef target_ref = m.Ref(broker());
if (target_ref.IsString()) {
StringRef str = target_ref.AsString();
if (str.length() == 1) {
// Ensure that the {string} is actually a String.
string = effect = graph()->NewNode(
simplified()->CheckString(p.feedback()), string, effect, control);
Node* string_length =
graph()->NewNode(simplified()->StringLength(), string);
Node* check =
graph()->NewNode(simplified()->NumberEqual(), string_length,
jsgraph()->ZeroConstant());
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check, control);
// Length of {string} is zero.
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->FalseConstant();
// Length of {string} is greater than zero.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = effect;
Node* vfalse;
{
Node* masked_position =
graph()->NewNode(simplified()->PoisonIndex(), position);
Node* string_first = efalse =
graph()->NewNode(simplified()->StringCharCodeAt(), string,
masked_position, efalse, control);
Node* search_first = jsgraph()->Constant(str.GetFirstChar());
vfalse = graph()->NewNode(simplified()->NumberEqual(), string_first,
search_first);
}
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue, vfalse, control);
effect =
graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
}
}
return NoChange();
}
// ES section 21.1.3.1 String.prototype.charAt ( pos )
Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
......
......@@ -120,6 +120,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceStringPrototypeStringAt(
const Operator* string_access_operator, Node* node);
Reduction ReduceStringPrototypeCharAt(Node* node);
Reduction ReduceStringPrototypeStartsWith(Node* node);
#ifdef V8_INTL_SUPPORT
Reduction ReduceStringPrototypeToLowerCaseIntl(Node* node);
......
// 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.
// Flags: --allow-natives-syntax --opt
(function() {
function foo(string) { return string.startsWith('a'); }
%PrepareFunctionForOptimization(foo);
assertEquals(false, foo(''));
assertEquals(true, foo('a'));
assertEquals(false, foo('ba'));
assertEquals(true, foo('abc'));
%OptimizeFunctionOnNextCall(foo);
assertEquals(false, foo(''));
assertEquals(true, foo('a'));
assertEquals(false, foo('ba'));
assertEquals(true, foo('abc'));
assertOptimized(foo);
})();
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