Commit d8d8f8b3 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[TurboFan] Add constant folding for StringConcat to NativeContextSpecialization.

Adds constant folding for the StringConcat bytecode to
NativeContextSpecialization. Can reduce operator to either a fully folded
constant string, or a JSAdd or a StringConcat with a reduced number of
operators.

BUG=v8:6243, chromium:738312

Change-Id: I6b2be6a3d95230a23f3c7390a4f7be5181c49a2a
Reviewed-on: https://chromium-review.googlesource.com/559146
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46461}
parent 52ea101f
......@@ -72,6 +72,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kJSAdd:
return ReduceJSAdd(node);
case IrOpcode::kJSStringConcat:
return ReduceJSStringConcat(node);
case IrOpcode::kJSGetSuperConstructor:
return ReduceJSGetSuperConstructor(node);
case IrOpcode::kJSInstanceOf:
......@@ -128,6 +130,59 @@ Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
return NoChange();
}
Reduction JSNativeContextSpecialization::ReduceJSStringConcat(Node* node) {
// TODO(turbofan): This has to run together with the inlining and
// native context specialization to be able to leverage the string
// constant-folding for optimizing property access, but we should
// nevertheless find a better home for this at some point.
DCHECK_EQ(IrOpcode::kJSStringConcat, node->opcode());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
DCHECK_GE(StringConcatParameterOf(node->op()).operand_count(), 3);
// Constant-fold string concatenation.
HeapObjectMatcher last_operand(NodeProperties::GetValueInput(node, 0));
int operand_count = StringConcatParameterOf(node->op()).operand_count();
for (int i = 1; i < operand_count; ++i) {
HeapObjectMatcher current_operand(NodeProperties::GetValueInput(node, i));
if (last_operand.HasValue() && current_operand.HasValue()) {
Handle<String> left = Handle<String>::cast(last_operand.Value());
Handle<String> right = Handle<String>::cast(current_operand.Value());
if (left->length() + right->length() <= String::kMaxLength) {
Handle<String> result =
factory()->NewConsString(left, right).ToHandleChecked();
Node* value = jsgraph()->HeapConstant(result);
node->ReplaceInput(i - 1, value);
node->RemoveInput(i);
last_operand = HeapObjectMatcher(value);
i--;
operand_count--;
continue;
}
}
last_operand = current_operand;
}
if (operand_count == StringConcatParameterOf(node->op()).operand_count()) {
return NoChange();
} else if (operand_count == 1) {
// Replace with input if there is only one input left.
Node* value = NodeProperties::GetValueInput(node, 0);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
} else if (operand_count == 2) {
// Replace with JSAdd if we only have two operands left.
NodeProperties::ChangeOp(node,
javascript()->Add(BinaryOperationHint::kString));
return Changed(node);
} else {
// Otherwise update operand count.
NodeProperties::ChangeOp(node, javascript()->StringConcat(operand_count));
return Changed(node);
}
}
Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
Node* node) {
DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode());
......
......@@ -54,6 +54,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
private:
Reduction ReduceJSAdd(Node* node);
Reduction ReduceJSStringConcat(Node* node);
Reduction ReduceJSGetSuperConstructor(Node* node);
Reduction ReduceJSInstanceOf(Node* node);
Reduction ReduceJSHasInPrototypeChain(Node* node);
......
// Copyright 2017 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
var foo = 'foo';
var bar = 'bar';
var a;
var b;
var c;
var d;
function baz() { return 'baz'; }
function test(arg) {
// All operands are constant folded by native context
// specialization / inlining.
a = '"' + foo + '-' + bar + '"';
b = '"' + foo + '-' + baz() + '"';
// Reduce down to a JSAdd of folded constant + arg.
c = foo + bar + arg;
// Reduces to a StringConcat with three operands.
d = '"' + foo + arg + bar + '"';
}
test('boo');
%OptimizeFunctionOnNextCall(test);
test('baa');
assertEquals('"foo-bar"', a);
assertEquals('"foo-baz"', b);
assertEquals('foobarbaa', c);
assertEquals('"foobaabar"', d);
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