Commit 2a90c39a authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[turbofan] Only save live registers on suspend

When suspending, rather than saving all registers up to a certain index,
only save the ones that are live according to the liveness analysis.
Others are saved as optimized out constants, and are skipped during the
GenaratorStore lowering. Symmetrically, only restore live registers when
resuming.

Change-Id: Icc2df905b0fe2fe5c372097bd67d5316edcd1b54
Reviewed-on: https://chromium-review.googlesource.com/905662
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51153}
parent 876f37c3
...@@ -2752,18 +2752,35 @@ void BytecodeGraphBuilder::VisitSuspendGenerator() { ...@@ -2752,18 +2752,35 @@ void BytecodeGraphBuilder::VisitSuspendGenerator() {
jsgraph()->Constant(bytecode_iterator().current_offset() + jsgraph()->Constant(bytecode_iterator().current_offset() +
(BytecodeArray::kHeaderSize - kHeapObjectTag)); (BytecodeArray::kHeaderSize - kHeapObjectTag));
const BytecodeLivenessState* liveness = bytecode_analysis()->GetInLivenessFor(
bytecode_iterator().current_offset());
// Maybe overallocate the value list since we don't know how many registers
// are live.
// TODO(leszeks): We could get this count from liveness rather than the
// register list.
int value_input_count = 3 + register_count; int value_input_count = 3 + register_count;
Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count); Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count);
value_inputs[0] = generator; value_inputs[0] = generator;
value_inputs[1] = suspend_id; value_inputs[1] = suspend_id;
value_inputs[2] = offset; value_inputs[2] = offset;
int count_written = 0;
for (int i = 0; i < register_count; ++i) { for (int i = 0; i < register_count; ++i) {
value_inputs[3 + i] = if (liveness == nullptr || liveness->RegisterIsLive(i)) {
while (count_written < i) {
value_inputs[3 + count_written++] = jsgraph()->OptimizedOutConstant();
}
value_inputs[3 + count_written++] =
environment()->LookupRegister(interpreter::Register(i)); environment()->LookupRegister(interpreter::Register(i));
DCHECK_EQ(count_written, i + 1);
}
} }
MakeNode(javascript()->GeneratorStore(register_count), value_input_count, // Use the actual written count rather than the register count to create the
// node.
MakeNode(javascript()->GeneratorStore(count_written), 3 + count_written,
value_inputs, false); value_inputs, false);
// TODO(leszeks): This over-approximates the liveness at exit, only the // TODO(leszeks): This over-approximates the liveness at exit, only the
...@@ -2849,15 +2866,20 @@ void BytecodeGraphBuilder::VisitResumeGenerator() { ...@@ -2849,15 +2866,20 @@ void BytecodeGraphBuilder::VisitResumeGenerator() {
interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1); interpreter::Register first_reg = bytecode_iterator().GetRegisterOperand(1);
// We assume we are restoring registers starting fromm index 0. // We assume we are restoring registers starting fromm index 0.
CHECK_EQ(0, first_reg.index()); CHECK_EQ(0, first_reg.index());
int register_count =
static_cast<int>(bytecode_iterator().GetRegisterCountOperand(2)); const BytecodeLivenessState* liveness =
bytecode_analysis()->GetOutLivenessFor(
bytecode_iterator().current_offset());
// Bijection between registers and array indices must match that used in // Bijection between registers and array indices must match that used in
// InterpreterAssembler::ExportRegisterFile. // InterpreterAssembler::ExportRegisterFile.
for (int i = 0; i < register_count; ++i) { for (int i = 0; i < environment()->register_count(); ++i) {
Node* value = NewNode(javascript()->GeneratorRestoreRegister(i), generator); if (liveness == nullptr || liveness->RegisterIsLive(i)) {
Node* value =
NewNode(javascript()->GeneratorRestoreRegister(i), generator);
environment()->BindRegister(interpreter::Register(i), value); environment()->BindRegister(interpreter::Register(i), value);
} }
}
// Update the accumulator with the generator's input_or_debug_pos. // Update the accumulator with the generator's input_or_debug_pos.
Node* input_or_debug_pos = Node* input_or_debug_pos =
......
...@@ -2034,10 +2034,12 @@ Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) { ...@@ -2034,10 +2034,12 @@ Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
for (int i = 0; i < register_count; ++i) { for (int i = 0; i < register_count; ++i) {
Node* value = NodeProperties::GetValueInput(node, 3 + i); Node* value = NodeProperties::GetValueInput(node, 3 + i);
if (value != jsgraph()->OptimizedOutConstant()) {
effect = graph()->NewNode( effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array, simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
value, effect, control); value, effect, control);
} }
}
effect = graph()->NewNode(simplified()->StoreField(context_field), generator, effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
context, effect, control); context, effect, control);
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --no-analyze-environment-liveness
// The functions used for testing backtraces. They are at the top to make the // The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier. // testing of source line/column easier.
......
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