Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Unified Diff: src/compiler/js-typed-lowering.cc

Issue 2354853002: [turbofan] Lower ConsString creation in JSTypedLowering. (Closed)
Patch Set: Address feedback. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/type-hint-analyzer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-typed-lowering.cc
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc
index 32d4fe6cba17192adb8bbc78785e6d85ef404f29..070d3cf818de5099dfa8ccb32991b7756dc8e560 100644
--- a/src/compiler/js-typed-lowering.cc
+++ b/src/compiler/js-typed-lowering.cc
@@ -46,6 +46,7 @@ class JSBinopReduction final {
return true;
case BinaryOperationHint::kAny:
case BinaryOperationHint::kNone:
+ case BinaryOperationHint::kString:
break;
}
}
@@ -73,6 +74,30 @@ class JSBinopReduction final {
return false;
}
+ // Check if a string addition will definitely result in creating a ConsString,
+ // i.e. if the combined length of the resulting string exceeds the ConsString
+ // minimum length.
+ bool ShouldCreateConsString() {
+ DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
+ if (BothInputsAre(Type::String()) ||
+ ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) &&
+ BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) {
+ if (left_type()->IsConstant() &&
+ left_type()->AsConstant()->Value()->IsString()) {
+ Handle<String> left_string =
+ Handle<String>::cast(left_type()->AsConstant()->Value());
+ if (left_string->length() >= ConsString::kMinLength) return true;
+ }
+ if (right_type()->IsConstant() &&
+ right_type()->AsConstant()->Value()->IsString()) {
+ Handle<String> right_string =
+ Handle<String>::cast(right_type()->AsConstant()->Value());
+ if (right_string->length() >= ConsString::kMinLength) return true;
+ }
+ }
+ return false;
+ }
+
void ConvertInputsToNumber() {
// To convert the inputs to numbers, we have to provide frame states
// for lazy bailouts in the ToNumber conversions.
@@ -467,6 +492,9 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
}
if (r.OneInputIs(Type::String())) {
+ if (r.ShouldCreateConsString()) {
+ return ReduceCreateConsString(node);
+ }
StringAddFlags flags = STRING_ADD_CHECK_NONE;
if (!r.LeftInputIs(Type::String())) {
flags = STRING_ADD_CONVERT_LEFT;
@@ -544,6 +572,123 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
return NoChange();
}
+Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
+ Node* first = NodeProperties::GetValueInput(node, 0);
+ Node* second = NodeProperties::GetValueInput(node, 1);
+ Node* context = NodeProperties::GetContextInput(node);
+ Node* frame_state = NodeProperties::GetFrameStateInput(node);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+
+ // Make sure {first} is actually a String.
+ Type* first_type = NodeProperties::GetType(first);
+ if (!first_type->Is(Type::String())) {
+ first = effect =
+ graph()->NewNode(simplified()->CheckString(), first, effect, control);
+ first_type = NodeProperties::GetType(first);
+ }
+
+ // Make sure {second} is actually a String.
+ Type* second_type = NodeProperties::GetType(second);
+ if (!second_type->Is(Type::String())) {
+ second = effect =
+ graph()->NewNode(simplified()->CheckString(), second, effect, control);
+ second_type = NodeProperties::GetType(second);
+ }
+
+ // Determine the {first} length.
+ Node* first_length =
+ first_type->IsConstant()
+ ? jsgraph()->Constant(
+ Handle<String>::cast(first_type->AsConstant()->Value())
+ ->length())
+ : effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForStringLength()),
+ first, effect, control);
+
+ // Determine the {second} length.
+ Node* second_length =
+ second_type->IsConstant()
+ ? jsgraph()->Constant(
+ Handle<String>::cast(second_type->AsConstant()->Value())
+ ->length())
+ : effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForStringLength()),
+ second, effect, control);
+
+ // Compute the resulting length.
+ Node* length =
+ graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
+
+ // Check if we would overflow the allowed maximum string length.
+ Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
+ jsgraph()->Constant(String::kMaxLength));
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* efalse = effect;
+ {
+ // Throw a RangeError in case of overflow.
+ Node* vfalse = efalse = graph()->NewNode(
+ javascript()->CallRuntime(Runtime::kThrowInvalidStringLength), context,
+ frame_state, efalse, if_false);
+ if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
+ if_false = graph()->NewNode(common()->Throw(), vfalse, efalse, if_false);
+ // TODO(bmeurer): This should be on the AdvancedReducer somehow.
+ NodeProperties::MergeControlToEnd(graph(), common(), if_false);
+ Revisit(graph()->end());
+
+ // Update potential {IfException} uses of {node} to point to the
+ // %ThrowInvalidStringLength runtime call node instead.
+ for (Edge edge : node->use_edges()) {
+ if (edge.from()->opcode() == IrOpcode::kIfException) {
+ DCHECK(NodeProperties::IsControlEdge(edge) ||
+ NodeProperties::IsEffectEdge(edge));
+ edge.UpdateTo(vfalse);
+ Revisit(edge.from());
+ }
+ }
+ }
+ control = graph()->NewNode(common()->IfTrue(), branch);
+
+ // Figure out the map for the resulting ConsString.
+ // TODO(turbofan): We currently just use the cons_string_map here for
+ // the sake of simplicity; we could also try to be smarter here and
+ // use the one_byte_cons_string_map instead when the resulting ConsString
+ // contains only one byte characters.
+ Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
+
+ // Allocate the resulting ConsString.
+ effect = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable), effect);
+ Node* value = effect =
+ graph()->NewNode(simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(ConsString::kSize), effect, control);
+ NodeProperties::SetType(value, Type::OtherString());
+ effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
+ value, value_map, effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForNameHashField()), value,
+ jsgraph()->Uint32Constant(Name::kEmptyHashField), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForStringLength()), value, length,
+ effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForConsStringFirst()), value,
+ first, effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForConsStringSecond()), value,
+ second, effect, control);
+
+ // Morph the {node} into a {FinishRegion}.
+ ReplaceWithValue(node, node, node, control);
+ node->ReplaceInput(0, value);
+ node->ReplaceInput(1, effect);
+ node->TrimInputCount(2);
+ NodeProperties::ChangeOp(node, common()->FinishRegion());
+ return Changed(node);
+}
+
Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::String())) {
« no previous file with comments | « src/compiler/js-typed-lowering.h ('k') | src/compiler/type-hint-analyzer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698