Commit db129b65 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Speculate on bounds checks for String#charAt and String#charCodeAt.

With the new builtin optimization guard we can just speculatively assume
that the index passed to String#charAt and String#charCodeAt (in optimized
code) is going to be within the valid range for the receiver. This is
what Crankshaft used to do, and it avoids Smi checks on the result for
String#charCodeAt, since it can no longer return NaN.

This gives rise to further optimizations of these builtins (i.e. to
completely avoid the tagging of char codes), and by itself already
improves the regression test originally reported from 650ms to
610ms.

Bug: v8:7127, v8:7326
Change-Id: Ia25a555c5c1a48d229c094b1ecd2487eec81e390
Reviewed-on: https://chromium-review.googlesource.com/872850Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50667}
parent f3d22635
......@@ -4047,7 +4047,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return Replace(value);
}
// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
// ES section #sec-string.prototype.charat
Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
......@@ -4060,52 +4060,32 @@ Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Ensure that the {receiver} is actually a String.
receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
receiver, effect, control);
if (node->op()->ValueInputCount() >= 3) {
index = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
NodeProperties::GetValueInput(node, 2),
effect, control);
// Map -0 and NaN to 0 (as per ToInteger), and the values in
// the [-2^31,-1] range to the [2^31,2^32-1] range, which will
// be considered out-of-bounds as well, because of the maximal
// String length limit in V8.
STATIC_ASSERT(String::kMaxLength <= kMaxInt);
index = graph()->NewNode(simplified()->NumberToUint32(), index);
}
// Determine the {receiver} length.
Node* receiver_length =
graph()->NewNode(simplified()->StringLength(), receiver);
// Check if {index} is less than {receiver} length.
Node* check =
graph()->NewNode(simplified()->NumberLessThan(), index, receiver_length);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
// Check that the {index} is within range (if specified).
if (node->op()->ValueInputCount() >= 3) {
index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
NodeProperties::GetValueInput(node, 2),
receiver_length, effect, control);
}
// Return the character from the {receiver} as single character string.
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* masked_index = graph()->NewNode(simplified()->MaskIndexWithBound(),
index, receiver_length);
Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
masked_index, if_true);
// Return the empty string otherwise.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = jsgraph()->EmptyStringConstant();
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
Node* value = graph()->NewNode(simplified()->StringCharAt(), receiver,
masked_index, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
// ES section #sec-string.prototype.charcodeat
Reduction JSCallReducer::ReduceStringPrototypeCharCodeAt(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
......@@ -4118,47 +4098,26 @@ Reduction JSCallReducer::ReduceStringPrototypeCharCodeAt(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Ensure that the {receiver} is actually a String.
receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()),
receiver, effect, control);
if (node->op()->ValueInputCount() >= 3) {
index = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()),
NodeProperties::GetValueInput(node, 2),
effect, control);
// Map -0 and NaN to 0 (as per ToInteger), and the values in
// the [-2^31,-1] range to the [2^31,2^32-1] range, which will
// be considered out-of-bounds as well, because of the maximal
// String length limit in V8.
STATIC_ASSERT(String::kMaxLength <= kMaxInt);
index = graph()->NewNode(simplified()->NumberToUint32(), index);
}
// Determine the {receiver} length.
Node* receiver_length =
graph()->NewNode(simplified()->StringLength(), receiver);
// Check if {index} is less than {receiver} length.
Node* check =
graph()->NewNode(simplified()->NumberLessThan(), index, receiver_length);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
// Check that the {index} is within range (if specified).
if (node->op()->ValueInputCount() >= 3) {
index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
NodeProperties::GetValueInput(node, 2),
receiver_length, effect, control);
}
// Load the character from the {receiver}.
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* masked_index = graph()->NewNode(simplified()->MaskIndexWithBound(),
index, receiver_length);
Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
masked_index, if_true);
// Return NaN otherwise.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = jsgraph()->NaNConstant();
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* value = graph()->NewNode(
common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);
Node* value = graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
masked_index, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
......
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