Commit da08dfc3 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Remove simplified operator StringCharAt

This CL now uses StringCharCodeAt + StringFromCharCode to replace
StringCharAt. Optimizations are easier to implement if we have both
operators; however, if this tanks performance a lot we have to revert.

R=bmeurer@chromium.org

Bug: v8:7531
Change-Id: I75590cc8b8db57715bc2de9f5b98d0878d62a394
Reviewed-on: https://chromium-review.googlesource.com/956134
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51877}
parent b0dc290a
...@@ -842,9 +842,6 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -842,9 +842,6 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringToNumber: case IrOpcode::kStringToNumber:
result = LowerStringToNumber(node); result = LowerStringToNumber(node);
break; break;
case IrOpcode::kStringCharAt:
result = LowerStringCharAt(node);
break;
case IrOpcode::kStringCharCodeAt: case IrOpcode::kStringCharCodeAt:
result = LowerStringCharCodeAt(node); result = LowerStringCharCodeAt(node);
break; break;
...@@ -2673,20 +2670,6 @@ Node* EffectControlLinearizer::LowerStringToNumber(Node* node) { ...@@ -2673,20 +2670,6 @@ Node* EffectControlLinearizer::LowerStringToNumber(Node* node) {
__ NoContextConstant()); __ NoContextConstant());
} }
Node* EffectControlLinearizer::LowerStringCharAt(Node* node) {
Node* receiver = node->InputAt(0);
Node* position = node->InputAt(1);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kStringCharAt);
Operator::Properties properties = Operator::kNoThrow | Operator::kNoWrite;
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
auto call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(call_descriptor, __ HeapConstant(callable.code()), receiver,
position, __ NoContextConstant());
}
Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) { Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) {
Node* receiver = node->InputAt(0); Node* receiver = node->InputAt(0);
Node* position = node->InputAt(1); Node* position = node->InputAt(1);
......
...@@ -116,7 +116,6 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -116,7 +116,6 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerSameValue(Node* node); Node* LowerSameValue(Node* node);
Node* LowerDeadValue(Node* node); Node* LowerDeadValue(Node* node);
Node* LowerStringToNumber(Node* node); Node* LowerStringToNumber(Node* node);
Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node); Node* LowerStringCharCodeAt(Node* node);
Node* LowerSeqStringCharCodeAt(Node* node); Node* LowerSeqStringCharCodeAt(Node* node);
Node* LowerStringCodePointAt(Node* node, UnicodeEncoding encoding); Node* LowerStringCodePointAt(Node* node, UnicodeEncoding encoding);
......
...@@ -3429,7 +3429,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node, ...@@ -3429,7 +3429,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
case Builtins::kStringPrototypeIndexOf: case Builtins::kStringPrototypeIndexOf:
return ReduceStringPrototypeIndexOf(node); return ReduceStringPrototypeIndexOf(node);
case Builtins::kStringPrototypeCharAt: case Builtins::kStringPrototypeCharAt:
return ReduceStringPrototypeStringAt(simplified()->StringCharAt(), node); return ReduceStringPrototypeCharAt(node);
case Builtins::kStringPrototypeCharCodeAt: case Builtins::kStringPrototypeCharCodeAt:
return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(), return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(),
node); node);
...@@ -4821,13 +4821,11 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { ...@@ -4821,13 +4821,11 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) {
return Replace(value); return Replace(value);
} }
// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
// ES6 section 21.1.3.3 String.prototype.codePointAt ( pos ) // ES6 section 21.1.3.3 String.prototype.codePointAt ( pos )
Reduction JSCallReducer::ReduceStringPrototypeStringAt( Reduction JSCallReducer::ReduceStringPrototypeStringAt(
const Operator* string_access_operator, Node* node) { const Operator* string_access_operator, Node* node) {
DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharAt || DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharCodeAt ||
string_access_operator->opcode() == IrOpcode::kStringCharCodeAt ||
string_access_operator->opcode() == IrOpcode::kStringCodePointAt); string_access_operator->opcode() == IrOpcode::kStringCodePointAt);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op()); CallParameters const& p = CallParametersOf(node->op());
...@@ -4864,6 +4862,45 @@ Reduction JSCallReducer::ReduceStringPrototypeStringAt( ...@@ -4864,6 +4862,45 @@ Reduction JSCallReducer::ReduceStringPrototypeStringAt(
return Replace(value); return Replace(value);
} }
// ES section 21.1.3.1 String.prototype.charAt ( pos )
Reduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* index = node->op()->ValueInputCount() >= 3
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->ZeroConstant();
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);
// Determine the {receiver} length.
Node* receiver_length =
graph()->NewNode(simplified()->StringLength(), receiver);
// Check that the {index} is within range.
index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()),
index, receiver_length, effect, control);
// Return the character from the {receiver} as single character string.
Node* masked_index = graph()->NewNode(simplified()->MaskIndexWithBound(),
index, receiver_length);
Node* value = effect =
graph()->NewNode(simplified()->StringCharCodeAt(), receiver, masked_index,
effect, control);
value = graph()->NewNode(simplified()->StringFromCharCode(), value);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) { Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) {
......
...@@ -116,6 +116,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer { ...@@ -116,6 +116,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceStringPrototypeSubstr(Node* node); Reduction ReduceStringPrototypeSubstr(Node* node);
Reduction ReduceStringPrototypeStringAt( Reduction ReduceStringPrototypeStringAt(
const Operator* string_access_operator, Node* node); const Operator* string_access_operator, Node* node);
Reduction ReduceStringPrototypeCharAt(Node* node);
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
Reduction ReduceStringPrototypeToLowerCaseIntl(Node* node); Reduction ReduceStringPrototypeToLowerCaseIntl(Node* node);
......
...@@ -2649,8 +2649,10 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad( ...@@ -2649,8 +2649,10 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
Node* if_true = graph()->NewNode(common()->IfTrue(), branch); Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue; Node* etrue;
Node* vtrue = etrue = graph()->NewNode( Node* vtrue = etrue =
simplified()->StringCharAt(), receiver, masked_index, *effect, if_true); graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
masked_index, *effect, if_true);
vtrue = graph()->NewNode(simplified()->StringFromCharCode(), vtrue);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch); Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* vfalse = jsgraph()->UndefinedConstant(); Node* vfalse = jsgraph()->UndefinedConstant();
...@@ -2671,8 +2673,9 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad( ...@@ -2671,8 +2673,9 @@ Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
// Return the character from the {receiver} as single character string. // Return the character from the {receiver} as single character string.
Node* value = *effect = Node* value = *effect =
graph()->NewNode(simplified()->StringCharAt(), receiver, masked_index, graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
*effect, *control); masked_index, *effect, *control);
value = graph()->NewNode(simplified()->StringFromCharCode(), value);
return value; return value;
} }
} }
......
...@@ -341,7 +341,6 @@ ...@@ -341,7 +341,6 @@
V(PlainPrimitiveToFloat64) \ V(PlainPrimitiveToFloat64) \
V(BooleanNot) \ V(BooleanNot) \
V(StringToNumber) \ V(StringToNumber) \
V(StringCharAt) \
V(StringCharCodeAt) \ V(StringCharCodeAt) \
V(SeqStringCharCodeAt) \ V(SeqStringCharCodeAt) \
V(StringCodePointAt) \ V(StringCodePointAt) \
......
...@@ -2349,11 +2349,6 @@ class RepresentationSelector { ...@@ -2349,11 +2349,6 @@ class RepresentationSelector {
return VisitBinop(node, UseInfo::AnyTagged(), return VisitBinop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer); MachineRepresentation::kTaggedPointer);
} }
case IrOpcode::kStringCharAt: {
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kStringCharCodeAt: { case IrOpcode::kStringCharCodeAt: {
Type* string_type = TypeOf(node->InputAt(0)); Type* string_type = TypeOf(node->InputAt(0));
if (string_type->Is(Type::SeqString())) { if (string_type->Is(Type::SeqString())) {
......
...@@ -721,7 +721,6 @@ bool operator==(CheckMinusZeroParameters const& lhs, ...@@ -721,7 +721,6 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(MaskIndexWithBound, Operator::kNoProperties, 2, 0) V(MaskIndexWithBound, Operator::kNoProperties, 2, 0)
#define EFFECT_DEPENDENT_OP_LIST(V) \ #define EFFECT_DEPENDENT_OP_LIST(V) \
V(StringCharAt, Operator::kNoProperties, 2, 1) \
V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(SeqStringCharCodeAt, Operator::kNoProperties, 2, 1) \ V(SeqStringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringSubstring, Operator::kNoProperties, 3, 1) V(StringSubstring, Operator::kNoProperties, 3, 1)
......
...@@ -522,7 +522,6 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -522,7 +522,6 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringEqual(); const Operator* StringEqual();
const Operator* StringLessThan(); const Operator* StringLessThan();
const Operator* StringLessThanOrEqual(); const Operator* StringLessThanOrEqual();
const Operator* StringCharAt();
const Operator* StringCharCodeAt(); const Operator* StringCharCodeAt();
const Operator* SeqStringCharCodeAt(); const Operator* SeqStringCharCodeAt();
const Operator* StringCodePointAt(UnicodeEncoding encoding); const Operator* StringCodePointAt(UnicodeEncoding encoding);
......
...@@ -1966,8 +1966,6 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) { ...@@ -1966,8 +1966,6 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) {
return Type::String(); return Type::String();
} }
Type* Typer::Visitor::TypeStringCharAt(Node* node) { return Type::String(); }
Type* Typer::Visitor::TypeStringToLowerCaseIntl(Node* node) { Type* Typer::Visitor::TypeStringToLowerCaseIntl(Node* node) {
return Type::String(); return Type::String();
} }
......
...@@ -1084,12 +1084,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -1084,12 +1084,6 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::String()); CheckValueInputIs(node, 0, Type::String());
CheckTypeIs(node, Type::Number()); CheckTypeIs(node, Type::Number());
break; break;
case IrOpcode::kStringCharAt:
// (String, Unsigned32) -> String
CheckValueInputIs(node, 0, Type::String());
CheckValueInputIs(node, 1, Type::Unsigned32());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kStringCharCodeAt: case IrOpcode::kStringCharCodeAt:
// (String, Unsigned32) -> UnsignedSmall // (String, Unsigned32) -> UnsignedSmall
CheckValueInputIs(node, 0, Type::String()); CheckValueInputIs(node, 0, Type::String());
......
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