| Index: src/compiler/js-builtin-reducer.cc
|
| diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
|
| index c8fe93d099138a94d4878d3fb2b8c727ce078d42..fa7f51d6ba2517cd456f509769571259a09ea0e8 100644
|
| --- a/src/compiler/js-builtin-reducer.cc
|
| +++ b/src/compiler/js-builtin-reducer.cc
|
| @@ -3,6 +3,8 @@
|
| // found in the LICENSE file.
|
|
|
| #include "src/compiler/js-builtin-reducer.h"
|
| +
|
| +#include "src/compiler/access-builder.h"
|
| #include "src/compiler/js-graph.h"
|
| #include "src/compiler/node-matchers.h"
|
| #include "src/compiler/node-properties.h"
|
| @@ -40,6 +42,10 @@ class JSCallReduction {
|
| return function->shared()->builtin_function_id();
|
| }
|
|
|
| + bool ReceiverMatches(Type* type) {
|
| + return NodeProperties::GetType(receiver())->Is(type);
|
| + }
|
| +
|
| // Determines whether the call takes zero inputs.
|
| bool InputsMatchZero() { return GetJSCallArity() == 0; }
|
|
|
| @@ -66,6 +72,7 @@ class JSCallReduction {
|
| return true;
|
| }
|
|
|
| + Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
|
| Node* left() { return GetJSCallInput(0); }
|
| Node* right() { return GetJSCallInput(1); }
|
|
|
| @@ -534,6 +541,127 @@ Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
|
| return NoChange();
|
| }
|
|
|
| +namespace {
|
| +
|
| +Node* GetStringReceiver(Node* node) {
|
| + Node* receiver = NodeProperties::GetValueInput(node, 1);
|
| + Type* receiver_type = NodeProperties::GetType(receiver);
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + if (receiver_type->Is(Type::String())) return receiver;
|
| + // Check if the {node} is dominated by a CheckString renaming for
|
| + // it's {receiver}, and if so use that renaming as {receiver} for
|
| + // the lowering below.
|
| + for (Node* dominator = effect;;) {
|
| + if (dominator->opcode() == IrOpcode::kCheckString &&
|
| + dominator->InputAt(0) == receiver) {
|
| + return dominator;
|
| + }
|
| + if (dominator->op()->EffectInputCount() != 1) {
|
| + // Didn't find any appropriate CheckString node.
|
| + return nullptr;
|
| + }
|
| + dominator = NodeProperties::GetEffectInput(dominator);
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
|
| +Reduction JSBuiltinReducer::ReduceStringCharAt(Node* node) {
|
| + // We need at least target, receiver and index parameters.
|
| + if (node->op()->ValueInputCount() >= 3) {
|
| + Node* index = NodeProperties::GetValueInput(node, 2);
|
| + Type* index_type = NodeProperties::GetType(index);
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + Node* control = NodeProperties::GetControlInput(node);
|
| +
|
| + if (index_type->Is(Type::Unsigned32())) {
|
| + if (Node* receiver = GetStringReceiver(node)) {
|
| + // Determine the {receiver} length.
|
| + Node* receiver_length = effect = graph()->NewNode(
|
| + simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
|
| + effect, control);
|
| +
|
| + // 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);
|
| +
|
| + Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* vtrue;
|
| + {
|
| + // Load the character from the {receiver}.
|
| + vtrue = graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
|
| + index, if_true);
|
| +
|
| + // Return it as single character string.
|
| + vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue);
|
| + }
|
| +
|
| + // 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);
|
| +
|
| + ReplaceWithValue(node, value, effect, control);
|
| + return Replace(value);
|
| + }
|
| + }
|
| + }
|
| +
|
| + return NoChange();
|
| +}
|
| +
|
| +// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
|
| +Reduction JSBuiltinReducer::ReduceStringCharCodeAt(Node* node) {
|
| + // We need at least target, receiver and index parameters.
|
| + if (node->op()->ValueInputCount() >= 3) {
|
| + Node* index = NodeProperties::GetValueInput(node, 2);
|
| + Type* index_type = NodeProperties::GetType(index);
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + Node* control = NodeProperties::GetControlInput(node);
|
| +
|
| + if (index_type->Is(Type::Unsigned32())) {
|
| + if (Node* receiver = GetStringReceiver(node)) {
|
| + // Determine the {receiver} length.
|
| + Node* receiver_length = effect = graph()->NewNode(
|
| + simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
|
| + effect, control);
|
| +
|
| + // 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);
|
| +
|
| + // Load the character from the {receiver}.
|
| + Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
|
| + receiver, 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);
|
| +
|
| + ReplaceWithValue(node, value, effect, control);
|
| + return Replace(value);
|
| + }
|
| + }
|
| + }
|
| +
|
| + return NoChange();
|
| +}
|
| +
|
| Reduction JSBuiltinReducer::Reduce(Node* node) {
|
| Reduction reduction = NoChange();
|
| JSCallReduction r(node);
|
| @@ -646,6 +774,10 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
| case kStringFromCharCode:
|
| reduction = ReduceStringFromCharCode(node);
|
| break;
|
| + case kStringCharAt:
|
| + return ReduceStringCharAt(node);
|
| + case kStringCharCodeAt:
|
| + return ReduceStringCharCodeAt(node);
|
| default:
|
| break;
|
| }
|
|
|