| Index: src/interpreter/bytecode-register-optimizer.cc
|
| diff --git a/src/interpreter/bytecode-register-optimizer.cc b/src/interpreter/bytecode-register-optimizer.cc
|
| index 01a46d23746e1b70f01bd54178498b2768c3db8c..563956e5c613456cbd5a9a8e1e0e48e627deaccf 100644
|
| --- a/src/interpreter/bytecode-register-optimizer.cc
|
| +++ b/src/interpreter/bytecode-register-optimizer.cc
|
| @@ -230,81 +230,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
|
| DCHECK(accumulator_info_->register_value() == accumulator_);
|
| }
|
|
|
| -// override
|
| -Handle<BytecodeArray> BytecodeRegisterOptimizer::ToBytecodeArray(
|
| - Isolate* isolate, int register_count, int parameter_count,
|
| - Handle<FixedArray> handler_table) {
|
| - FlushState();
|
| - return next_stage_->ToBytecodeArray(isolate, max_register_index_ + 1,
|
| - parameter_count, handler_table);
|
| -}
|
| -
|
| -// override
|
| -void BytecodeRegisterOptimizer::Write(BytecodeNode* node) {
|
| - // Jumps are handled by WriteJump.
|
| - DCHECK(!Bytecodes::IsJump(node->bytecode()));
|
| - //
|
| - // Transfers with observable registers as the destination will be
|
| - // immediately materialized so the source position information will
|
| - // be ordered correctly.
|
| - //
|
| - // Transfers without observable destination registers will initially
|
| - // be emitted as Nop's with the source position. They may, or may
|
| - // not, be materialized by the optimizer. However, the source
|
| - // position is not lost and being attached to a Nop is fine as the
|
| - // destination register is not observable in the debugger.
|
| - //
|
| - switch (node->bytecode()) {
|
| - case Bytecode::kLdar: {
|
| - DoLdar(node);
|
| - return;
|
| - }
|
| - case Bytecode::kStar: {
|
| - DoStar(node);
|
| - return;
|
| - }
|
| - case Bytecode::kMov: {
|
| - DoMov(node);
|
| - return;
|
| - }
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - if (node->bytecode() == Bytecode::kDebugger ||
|
| - node->bytecode() == Bytecode::kSuspendGenerator) {
|
| - // All state must be flushed before emitting
|
| - // - a call to the debugger (as it can manipulate locals and parameters),
|
| - // - a generator suspend (as this involves saving all registers).
|
| - FlushState();
|
| - }
|
| -
|
| - PrepareOperands(node);
|
| - next_stage_->Write(node);
|
| -}
|
| -
|
| -// override
|
| -void BytecodeRegisterOptimizer::WriteJump(BytecodeNode* node,
|
| - BytecodeLabel* label) {
|
| - FlushState();
|
| - next_stage_->WriteJump(node, label);
|
| -}
|
| -
|
| -// override
|
| -void BytecodeRegisterOptimizer::BindLabel(BytecodeLabel* label) {
|
| - FlushState();
|
| - next_stage_->BindLabel(label);
|
| -}
|
| -
|
| -// override
|
| -void BytecodeRegisterOptimizer::BindLabel(const BytecodeLabel& target,
|
| - BytecodeLabel* label) {
|
| - // There is no need to flush here, it will have been flushed when |target|
|
| - // was bound.
|
| - next_stage_->BindLabel(target, label);
|
| -}
|
| -
|
| -void BytecodeRegisterOptimizer::FlushState() {
|
| +void BytecodeRegisterOptimizer::Flush() {
|
| if (!flush_required_) {
|
| return;
|
| }
|
| @@ -332,7 +258,7 @@ void BytecodeRegisterOptimizer::FlushState() {
|
|
|
| void BytecodeRegisterOptimizer::OutputRegisterTransfer(
|
| RegisterInfo* input_info, RegisterInfo* output_info,
|
| - BytecodeSourceInfo* source_info) {
|
| + BytecodeSourceInfo source_info) {
|
| Register input = input_info->register_value();
|
| Register output = output_info->register_value();
|
| DCHECK_NE(input.index(), output.index());
|
| @@ -404,7 +330,7 @@ void BytecodeRegisterOptimizer::AddToEquivalenceSet(
|
|
|
| void BytecodeRegisterOptimizer::RegisterTransfer(
|
| RegisterInfo* input_info, RegisterInfo* output_info,
|
| - BytecodeSourceInfo* source_info) {
|
| + BytecodeSourceInfo source_info) {
|
| // Materialize an alternate in the equivalence set that
|
| // |output_info| is leaving.
|
| if (output_info->materialized()) {
|
| @@ -423,7 +349,7 @@ void BytecodeRegisterOptimizer::RegisterTransfer(
|
| output_info->set_materialized(false);
|
| RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent();
|
| OutputRegisterTransfer(materialized_info, output_info, source_info);
|
| - } else if (source_info->is_valid()) {
|
| + } else if (source_info.is_valid()) {
|
| // Emit a placeholder nop to maintain source position info.
|
| EmitNopForSourceInfo(source_info);
|
| }
|
| @@ -437,60 +363,32 @@ void BytecodeRegisterOptimizer::RegisterTransfer(
|
| }
|
|
|
| void BytecodeRegisterOptimizer::EmitNopForSourceInfo(
|
| - BytecodeSourceInfo* source_info) const {
|
| - DCHECK(source_info->is_valid());
|
| + BytecodeSourceInfo source_info) const {
|
| + DCHECK(source_info.is_valid());
|
| BytecodeNode nop(Bytecode::kNop, source_info);
|
| next_stage_->Write(&nop);
|
| }
|
|
|
| -void BytecodeRegisterOptimizer::DoLdar(BytecodeNode* node) {
|
| - Register input = GetRegisterInputOperand(
|
| - 0, node->bytecode(), node->operands(), node->operand_count());
|
| - RegisterInfo* input_info = GetRegisterInfo(input);
|
| - RegisterTransfer(input_info, accumulator_info_, node->source_info_ptr());
|
| -}
|
| -
|
| -void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) {
|
| - Register input = GetRegisterInputOperand(
|
| - 0, node->bytecode(), node->operands(), node->operand_count());
|
| - RegisterInfo* input_info = GetRegisterInfo(input);
|
| - Register output = GetRegisterOutputOperand(
|
| - 1, node->bytecode(), node->operands(), node->operand_count());
|
| - RegisterInfo* output_info = GetRegisterInfo(output);
|
| - RegisterTransfer(input_info, output_info, node->source_info_ptr());
|
| -}
|
| -
|
| -void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) {
|
| - Register output = GetRegisterOutputOperand(
|
| - 0, node->bytecode(), node->operands(), node->operand_count());
|
| - RegisterInfo* output_info = GetRegisterInfo(output);
|
| - RegisterTransfer(accumulator_info_, output_info, node->source_info_ptr());
|
| -}
|
| -
|
| -void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand(
|
| - RegisterInfo* reg_info) {
|
| +void BytecodeRegisterOptimizer::PrepareOutputRegister(Register reg) {
|
| + RegisterInfo* reg_info = GetRegisterInfo(reg);
|
| if (reg_info->materialized()) {
|
| CreateMaterializedEquivalent(reg_info);
|
| }
|
| + reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
|
| max_register_index_ =
|
| std::max(max_register_index_, reg_info->register_value().index());
|
| - reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
|
| }
|
|
|
| -void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand(
|
| - Register start, int count) {
|
| - for (int i = 0; i < count; ++i) {
|
| - Register reg(start.index() + i);
|
| - RegisterInfo* reg_info = GetRegisterInfo(reg);
|
| - PrepareRegisterOutputOperand(reg_info);
|
| +void BytecodeRegisterOptimizer::PrepareOutputRegisterList(
|
| + RegisterList reg_list) {
|
| + int start_index = reg_list.first_register().index();
|
| + for (int i = 0; i < reg_list.register_count(); ++i) {
|
| + Register current(start_index + i);
|
| + PrepareOutputRegister(current);
|
| }
|
| }
|
|
|
| -Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand(
|
| - Register reg) {
|
| - // For a temporary register, RegInfo state may need be created. For
|
| - // locals and parameters, the RegInfo state is created in the
|
| - // BytecodeRegisterOptimizer constructor.
|
| +Register BytecodeRegisterOptimizer::GetInputRegister(Register reg) {
|
| RegisterInfo* reg_info = GetRegisterInfo(reg);
|
| if (reg_info->materialized()) {
|
| return reg;
|
| @@ -501,124 +399,49 @@ Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand(
|
| }
|
| }
|
|
|
| -void BytecodeRegisterOptimizer::PrepareRegisterInputOperand(
|
| - BytecodeNode* const node, Register reg, int operand_index) {
|
| - Register equivalent = GetEquivalentRegisterForInputOperand(reg);
|
| - node->UpdateOperand(operand_index,
|
| - static_cast<uint32_t>(equivalent.ToOperand()));
|
| -}
|
| -
|
| -void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start,
|
| - int count) {
|
| - for (int i = 0; i < count; ++i) {
|
| - Register current(start.index() + i);
|
| - RegisterInfo* input_info = GetRegisterInfo(current);
|
| - Materialize(input_info);
|
| +RegisterList BytecodeRegisterOptimizer::GetInputRegisterList(
|
| + RegisterList reg_list) {
|
| + if (reg_list.register_count() == 1) {
|
| + // If there is only a single register, treat it as a normal input register.
|
| + Register reg(GetInputRegister(reg_list.first_register()));
|
| + return RegisterList(reg.index(), 1);
|
| + } else {
|
| + int start_index = reg_list.first_register().index();
|
| + for (int i = 0; i < reg_list.register_count(); ++i) {
|
| + Register current(start_index + i);
|
| + RegisterInfo* input_info = GetRegisterInfo(current);
|
| + Materialize(input_info);
|
| + }
|
| + return reg_list;
|
| }
|
| }
|
|
|
| -void BytecodeRegisterOptimizer::PrepareRegisterOperands(
|
| - BytecodeNode* const node) {
|
| - //
|
| - // For each input operand, get a materialized equivalent if it is
|
| - // just a single register, otherwise materialize register range.
|
| - // Update operand_scale if necessary.
|
| - //
|
| - // For each output register about to be clobbered, materialize an
|
| - // equivalent if it exists. Put each register in it's own equivalence set.
|
| - //
|
| - const uint32_t* operands = node->operands();
|
| - int operand_count = node->operand_count();
|
| - const OperandType* operand_types =
|
| - Bytecodes::GetOperandTypes(node->bytecode());
|
| - for (int i = 0; i < operand_count; ++i) {
|
| - int count;
|
| - if (operand_types[i] == OperandType::kRegList) {
|
| - DCHECK_LT(i, operand_count - 1);
|
| - DCHECK(operand_types[i + 1] == OperandType::kRegCount);
|
| - count = static_cast<int>(operands[i + 1]);
|
| - } else {
|
| - count = Bytecodes::GetNumberOfRegistersRepresentedBy(operand_types[i]);
|
| - }
|
| -
|
| - if (count == 0) {
|
| - continue;
|
| - }
|
| -
|
| - Register reg = Register::FromOperand(static_cast<int32_t>(operands[i]));
|
| - if (Bytecodes::IsRegisterInputOperandType(operand_types[i])) {
|
| - if (count == 1) {
|
| - PrepareRegisterInputOperand(node, reg, i);
|
| - } else if (count > 1) {
|
| - PrepareRegisterRangeInputOperand(reg, count);
|
| - }
|
| - } else if (Bytecodes::IsRegisterOutputOperandType(operand_types[i])) {
|
| - PrepareRegisterRangeOutputOperand(reg, count);
|
| - }
|
| +void BytecodeRegisterOptimizer::PrepareForBytecode(Bytecode bytecode) {
|
| + if (Bytecodes::IsJump(bytecode) || bytecode == Bytecode::kDebugger ||
|
| + bytecode == Bytecode::kSuspendGenerator) {
|
| + // All state must be flushed before emitting
|
| + // - a jump bytecode (as the register equivalents at the jump target aren't
|
| + // known.
|
| + // - a call to the debugger (as it can manipulate locals and parameters),
|
| + // - a generator suspend (as this involves saving all registers).
|
| + Flush();
|
| }
|
| -}
|
|
|
| -void BytecodeRegisterOptimizer::PrepareAccumulator(BytecodeNode* const node) {
|
| // Materialize the accumulator if it is read by the bytecode. The
|
| // accumulator is special and no other register can be materialized
|
| // in it's place.
|
| - if (Bytecodes::ReadsAccumulator(node->bytecode()) &&
|
| + if (Bytecodes::ReadsAccumulator(bytecode) &&
|
| !accumulator_info_->materialized()) {
|
| Materialize(accumulator_info_);
|
| }
|
|
|
| // Materialize an equivalent to the accumulator if it will be
|
| // clobbered when the bytecode is dispatched.
|
| - if (Bytecodes::WritesAccumulator(node->bytecode())) {
|
| - PrepareRegisterOutputOperand(accumulator_info_);
|
| + if (Bytecodes::WritesAccumulator(bytecode)) {
|
| + PrepareOutputRegister(accumulator_);
|
| }
|
| }
|
|
|
| -void BytecodeRegisterOptimizer::PrepareOperands(BytecodeNode* const node) {
|
| - PrepareAccumulator(node);
|
| - PrepareRegisterOperands(node);
|
| -}
|
| -
|
| -// static
|
| -Register BytecodeRegisterOptimizer::GetRegisterInputOperand(
|
| - int index, Bytecode bytecode, const uint32_t* operands, int operand_count) {
|
| - DCHECK_LT(index, operand_count);
|
| - DCHECK(Bytecodes::IsRegisterInputOperandType(
|
| - Bytecodes::GetOperandType(bytecode, index)));
|
| - return OperandToRegister(operands[index]);
|
| -}
|
| -
|
| -// static
|
| -Register BytecodeRegisterOptimizer::GetRegisterOutputOperand(
|
| - int index, Bytecode bytecode, const uint32_t* operands, int operand_count) {
|
| - DCHECK_LT(index, operand_count);
|
| - DCHECK(Bytecodes::IsRegisterOutputOperandType(
|
| - Bytecodes::GetOperandType(bytecode, index)));
|
| - return OperandToRegister(operands[index]);
|
| -}
|
| -
|
| -BytecodeRegisterOptimizer::RegisterInfo*
|
| -BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) {
|
| - size_t index = GetRegisterInfoTableIndex(reg);
|
| - DCHECK_LT(index, register_info_table_.size());
|
| - return register_info_table_[index];
|
| -}
|
| -
|
| -BytecodeRegisterOptimizer::RegisterInfo*
|
| -BytecodeRegisterOptimizer::GetOrCreateRegisterInfo(Register reg) {
|
| - size_t index = GetRegisterInfoTableIndex(reg);
|
| - return index < register_info_table_.size() ? register_info_table_[index]
|
| - : NewRegisterInfo(reg);
|
| -}
|
| -
|
| -BytecodeRegisterOptimizer::RegisterInfo*
|
| -BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) {
|
| - size_t index = GetRegisterInfoTableIndex(reg);
|
| - DCHECK_GE(index, register_info_table_.size());
|
| - GrowRegisterMap(reg);
|
| - return register_info_table_[index];
|
| -}
|
| -
|
| void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
|
| DCHECK(RegisterIsTemporary(reg));
|
| size_t index = GetRegisterInfoTableIndex(reg);
|
|
|