Commit 1ea0b91a authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Make ForInPrepare take a kRegTriple8 and ForInNext take kRegPair8 for cache state

Make ForInPrepare take a kRegTriple8 operand and ForInNext take kRegPair8
operand for cache state. This is to ensure that the cache state output of
ForInPrepare is in consecutive registers to allow us to deopt the
ForInPrepare node from TF->Ignition (to be done in a followup CL).

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1584813002

Cr-Commit-Position: refs/heads/master@{#33357}
parent 107db2ca
......@@ -1724,19 +1724,11 @@ void BytecodeGraphBuilder::VisitReturn(
void BytecodeGraphBuilder::VisitForInPrepare(
const interpreter::BytecodeArrayIterator& iterator) {
Node* prepare = nullptr;
{
FrameStateBeforeAndAfter states(this, iterator);
Node* receiver = environment()->LookupAccumulator();
prepare = NewNode(javascript()->ForInPrepare(), receiver);
environment()->RecordAfterState(prepare, &states);
}
// Project cache_type, cache_array, cache_length into register
// operands 1, 2, 3.
for (int i = 0; i < 3; i++) {
environment()->BindRegister(iterator.GetRegisterOperand(i),
NewNode(common()->Projection(i), prepare));
}
FrameStateBeforeAndAfter states(this, iterator);
Node* receiver = environment()->LookupAccumulator();
Node* prepare = NewNode(javascript()->ForInPrepare(), receiver);
environment()->BindRegistersToProjections(iterator.GetRegisterOperand(0),
prepare, &states);
}
......@@ -1756,11 +1748,13 @@ void BytecodeGraphBuilder::VisitForInNext(
FrameStateBeforeAndAfter states(this, iterator);
Node* receiver =
environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* cache_type =
environment()->LookupRegister(iterator.GetRegisterOperand(1));
Node* cache_array =
environment()->LookupRegister(iterator.GetRegisterOperand(2));
Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(3));
Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(1));
int catch_reg_pair_index = iterator.GetRegisterOperand(2).index();
Node* cache_type = environment()->LookupRegister(
interpreter::Register(catch_reg_pair_index));
Node* cache_array = environment()->LookupRegister(
interpreter::Register(catch_reg_pair_index + 1));
Node* value = NewNode(javascript()->ForInNext(), receiver, cache_array,
cache_type, index);
environment()->BindAccumulator(value, &states);
......
......@@ -304,6 +304,7 @@ Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
switch (interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)) {
case interpreter::OperandType::kReg8:
case interpreter::OperandType::kRegPair8:
case interpreter::OperandType::kRegTriple8:
case interpreter::OperandType::kMaybeReg8:
DCHECK_EQ(
interpreter::OperandSize::kByte,
......
......@@ -981,9 +981,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
Register cache_type, Register cache_array, Register cache_length) {
Output(Bytecode::kForInPrepare, cache_type.ToOperand(),
cache_array.ToOperand(), cache_length.ToOperand());
Register cache_info_triple) {
Output(Bytecode::kForInPrepare, cache_info_triple.ToOperand());
return *this;
}
......@@ -995,12 +994,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(Register receiver,
Register cache_type,
Register cache_array,
Register index) {
Output(Bytecode::kForInNext, receiver.ToOperand(), cache_type.ToOperand(),
cache_array.ToOperand(), index.ToOperand());
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
Register receiver, Register index, Register cache_type_array_pair) {
Output(Bytecode::kForInNext, receiver.ToOperand(), index.ToOperand(),
cache_type_array_pair.ToOperand());
return *this;
}
......@@ -1256,6 +1253,14 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
Register reg1 = Register(reg0.index() + 1);
return RegisterIsValid(reg0) && RegisterIsValid(reg1);
}
case OperandType::kRegTriple8: {
Register reg0 =
Register::FromOperand(static_cast<uint8_t>(operand_value));
Register reg1 = Register(reg0.index() + 1);
Register reg2 = Register(reg0.index() + 2);
return RegisterIsValid(reg0) && RegisterIsValid(reg1) &&
RegisterIsValid(reg2);
}
case OperandType::kReg16:
if (bytecode != Bytecode::kExchange &&
bytecode != Bytecode::kExchangeWide) {
......
......@@ -221,11 +221,10 @@ class BytecodeArrayBuilder final {
BytecodeArrayBuilder& Return();
// Complex flow control.
BytecodeArrayBuilder& ForInPrepare(Register cache_type, Register cache_array,
Register cache_length);
BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple);
BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
BytecodeArrayBuilder& ForInNext(Register receiver, Register cache_type,
Register cache_array, Register index);
BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
Register cache_type_array_pair);
BytecodeArrayBuilder& ForInStep(Register index);
// Accessors
......
......@@ -89,6 +89,7 @@ Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(operand_type == OperandType::kReg8 ||
operand_type == OperandType::kRegPair8 ||
operand_type == OperandType::kRegTriple8 ||
operand_type == OperandType::kMaybeReg8 ||
operand_type == OperandType::kReg16);
uint32_t operand = GetRawOperand(operand_index, operand_type);
......
......@@ -858,10 +858,14 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->CastAccumulatorToJSObject();
builder()->JumpIfNull(&not_object_label);
builder()->StoreAccumulatorInRegister(receiver);
Register cache_type = register_allocator()->NewRegister();
Register cache_array = register_allocator()->NewRegister();
Register cache_length = register_allocator()->NewRegister();
builder()->ForInPrepare(cache_type, cache_array, cache_length);
register_allocator()->PrepareForConsecutiveAllocations(3);
Register cache_type = register_allocator()->NextConsecutiveRegister();
Register cache_array = register_allocator()->NextConsecutiveRegister();
Register cache_length = register_allocator()->NextConsecutiveRegister();
// Used as kRegTriple8 and kRegPair8 in ForInPrepare and ForInNext.
USE(cache_array);
builder()->ForInPrepare(cache_type);
// Set up loop counter
Register index = register_allocator()->NewRegister();
......@@ -873,7 +877,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
loop_builder.Condition();
builder()->ForInDone(index, cache_length);
loop_builder.BreakIfTrue();
builder()->ForInNext(receiver, cache_type, cache_array, index);
DCHECK(Register::AreContiguous(cache_type, cache_array));
builder()->ForInNext(receiver, index, cache_type);
loop_builder.ContinueIfUndefined();
VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
Visit(stmt->body());
......
......@@ -293,14 +293,16 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
}
break;
}
case interpreter::OperandType::kRegPair8: {
case interpreter::OperandType::kRegPair8:
case interpreter::OperandType::kRegTriple8: {
Register reg = Register::FromOperand(*operand_start);
int range = op_type == interpreter::OperandType::kRegPair8 ? 1 : 2;
if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count);
DCHECK_NE(parameter_index, 0);
os << "a" << parameter_index - 1 << "-" << parameter_index;
os << "a" << parameter_index - range << "-" << parameter_index;
} else {
os << "r" << reg.index() << "-" << reg.index() + 1;
os << "r" << reg.index() << "-" << reg.index() + range;
}
break;
}
......
......@@ -16,22 +16,23 @@ namespace internal {
namespace interpreter {
// The list of operand types used by bytecodes.
#define OPERAND_TYPE_LIST(V) \
\
/* None operand. */ \
V(None, OperandSize::kNone) \
\
/* Byte operands. */ \
V(Count8, OperandSize::kByte) \
V(Imm8, OperandSize::kByte) \
V(Idx8, OperandSize::kByte) \
V(MaybeReg8, OperandSize::kByte) \
V(Reg8, OperandSize::kByte) \
V(RegPair8, OperandSize::kByte) \
\
/* Short operands. */ \
V(Count16, OperandSize::kShort) \
V(Idx16, OperandSize::kShort) \
#define OPERAND_TYPE_LIST(V) \
\
/* None operand. */ \
V(None, OperandSize::kNone) \
\
/* Byte operands. */ \
V(Count8, OperandSize::kByte) \
V(Imm8, OperandSize::kByte) \
V(Idx8, OperandSize::kByte) \
V(MaybeReg8, OperandSize::kByte) \
V(Reg8, OperandSize::kByte) \
V(RegPair8, OperandSize::kByte) \
V(RegTriple8, OperandSize::kByte) \
\
/* Short operands. */ \
V(Count16, OperandSize::kShort) \
V(Idx16, OperandSize::kShort) \
V(Reg16, OperandSize::kShort)
// The list of bytecodes which are interpreted by the interpreter.
......@@ -219,10 +220,9 @@ namespace interpreter {
V(JumpIfUndefinedConstantWide, OperandType::kIdx16) \
\
/* Complex flow control For..in */ \
V(ForInPrepare, OperandType::kReg8, OperandType::kReg8, OperandType::kReg8) \
V(ForInPrepare, OperandType::kRegTriple8) \
V(ForInDone, OperandType::kReg8, OperandType::kReg8) \
V(ForInNext, OperandType::kReg8, OperandType::kReg8, OperandType::kReg8, \
OperandType::kReg8) \
V(ForInNext, OperandType::kReg8, OperandType::kReg8, OperandType::kRegPair8) \
V(ForInStep, OperandType::kReg8) \
\
/* Non-local flow control */ \
......
......@@ -1709,39 +1709,41 @@ void Interpreter::DoReturn(compiler::InterpreterAssembler* assembler) {
}
// ForInPrepare <cache_type> <cache_array> <cache_length>
// ForInPrepare <cache_info_triple>
//
// Returns state for for..in loop execution based on the object in the
// accumulator. The registers |cache_type|, |cache_array|, and
// |cache_length| represent output parameters.
// accumulator. The result is output in registers |cache_info_triple| to
// |cache_info_triple + 2|, with the registers holding cache_type, cache_array,
// and cache_length respectively.
void Interpreter::DoForInPrepare(compiler::InterpreterAssembler* assembler) {
Node* object = __ GetAccumulator();
Node* result_triple = __ CallRuntime(Runtime::kForInPrepare, object);
// Set output registers:
// 0 == cache_type, 1 == cache_array, 2 == cache_length
Node* output_register = __ BytecodeOperandReg(0);
for (int i = 0; i < 3; i++) {
Node* cache_info = __ Projection(i, result_triple);
Node* cache_info_reg = __ BytecodeOperandReg(i);
__ StoreRegister(cache_info, cache_info_reg);
__ StoreRegister(cache_info, output_register);
output_register = __ NextRegister(output_register);
}
__ Dispatch();
}
// ForInNext <receiver> <cache_type> <cache_array> <index>
// ForInNext <receiver> <index> <cache_info_pair>
//
// Returns the next enumerable property in the the accumulator.
void Interpreter::DoForInNext(compiler::InterpreterAssembler* assembler) {
Node* receiver_reg = __ BytecodeOperandReg(0);
Node* receiver = __ LoadRegister(receiver_reg);
Node* cache_type_reg = __ BytecodeOperandReg(1);
Node* index_reg = __ BytecodeOperandReg(1);
Node* index = __ LoadRegister(index_reg);
Node* cache_type_reg = __ BytecodeOperandReg(2);
Node* cache_type = __ LoadRegister(cache_type_reg);
Node* cache_array_reg = __ BytecodeOperandReg(2);
Node* cache_array_reg = __ NextRegister(cache_type_reg);
Node* cache_array = __ LoadRegister(cache_array_reg);
Node* index_reg = __ BytecodeOperandReg(3);
Node* index = __ LoadRegister(index_reg);
Node* result = __ CallRuntime(Runtime::kForInNext, receiver, cache_array,
cache_type, index);
__ SetAccumulator(result);
......
......@@ -5249,30 +5249,30 @@ TEST(ForIn) {
"for (var p in x) { return p; }",
8 * kPointerSize,
1,
45,
42,
{
B(LdaConstant), U8(0), //
B(Star), R(1), //
B(JumpIfUndefined), U8(39), //
B(JumpIfNull), U8(37), //
B(ToObject), //
B(JumpIfNull), U8(34), //
B(Star), R(3), //
B(ForInPrepare), R(4), R(5), R(6), //
B(LdaZero), //
B(Star), R(7), //
B(ForInDone), R(7), R(6), //
B(JumpIfTrue), U8(20), //
B(ForInNext), R(3), R(4), R(5), R(7), //
B(JumpIfUndefined), U8(7), //
B(Star), R(0), //
B(Star), R(2), //
B(Return), //
B(ForInStep), R(7), //
B(Star), R(7), //
B(Jump), U8(-21), //
B(LdaUndefined), //
B(Return), //
B(LdaConstant), U8(0), //
B(Star), R(1), //
B(JumpIfUndefined), U8(36), //
B(JumpIfNull), U8(34), //
B(ToObject), //
B(JumpIfNull), U8(31), //
B(Star), R(3), //
B(ForInPrepare), R(4), //
B(LdaZero), //
B(Star), R(7), //
B(ForInDone), R(7), R(6), //
B(JumpIfTrue), U8(19), //
B(ForInNext), R(3), R(7), R(4), //
B(JumpIfUndefined), U8(7), //
B(Star), R(0), //
B(Star), R(2), //
B(Return), //
B(ForInStep), R(7), //
B(Star), R(7), //
B(Jump), U8(-20), //
B(LdaUndefined), //
B(Return), //
},
1,
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
......@@ -5280,22 +5280,22 @@ TEST(ForIn) {
"for (var p in [1,2,3]) { x += p; }",
9 * kPointerSize,
1,
57,
54,
{
B(LdaZero), //
B(Star), R(1), //
B(CreateArrayLiteral), U8(0), U8(0), U8(3), //
B(JumpIfUndefined), U8(48), //
B(JumpIfNull), U8(46), //
B(ToObject), //
B(JumpIfUndefined), U8(45), //
B(JumpIfNull), U8(43), //
B(ToObject), //
B(JumpIfNull), U8(40), //
B(Star), R(3), //
B(ForInPrepare), R(4), R(5), R(6), //
B(ForInPrepare), R(4), //
B(LdaZero), //
B(Star), R(7), //
B(ForInDone), R(7), R(6), //
B(JumpIfTrue), U8(29), //
B(ForInNext), R(3), R(4), R(5), R(7), //
B(JumpIfTrue), U8(28), //
B(ForInNext), R(3), R(7), R(4), //
B(JumpIfUndefined), U8(16), //
B(Star), R(0), //
B(Star), R(2), //
......@@ -5306,7 +5306,7 @@ TEST(ForIn) {
B(Star), R(1), //
B(ForInStep), R(7), //
B(Star), R(7), //
B(Jump), U8(-30), //
B(Jump), U8(-29), //
B(LdaUndefined), //
B(Return), //
},
......@@ -5319,22 +5319,22 @@ TEST(ForIn) {
"}",
8 * kPointerSize,
1,
94,
91,
{
B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), //
B(Star), R(0), //
B(CreateArrayLiteral), U8(1), U8(1), U8(simple_flags), //
B(JumpIfUndefined), U8(82), //
B(JumpIfNull), U8(80), //
B(ToObject), //
B(JumpIfUndefined), U8(79), //
B(JumpIfNull), U8(77), //
B(ToObject), //
B(JumpIfNull), U8(74), //
B(Star), R(1), //
B(ForInPrepare), R(2), R(3), R(4), //
B(ForInPrepare), R(2), //
B(LdaZero), //
B(Star), R(5), //
B(ForInDone), R(5), R(4), //
B(JumpIfTrue), U8(63), //
B(ForInNext), R(1), R(2), R(3), R(5), //
B(JumpIfTrue), U8(62), //
B(ForInNext), R(1), R(5), R(2), //
B(JumpIfUndefined), U8(50), //
B(Star), R(6), //
B(Ldar), R(0), //
......@@ -5359,7 +5359,7 @@ TEST(ForIn) {
B(Jump), U8(8), //
B(ForInStep), R(5), //
B(Star), R(5), //
B(Jump), U8(-64), //
B(Jump), U8(-63), //
B(LdaUndefined), //
B(Return), //
},
......@@ -5370,22 +5370,22 @@ TEST(ForIn) {
"for (x[0] in [1,2,3]) { return x[3]; }",
9 * kPointerSize,
1,
71,
68,
{
B(CreateArrayLiteral), U8(0), U8(0), U8(simple_flags), //
B(Star), R(0), //
B(CreateArrayLiteral), U8(1), U8(1), U8(simple_flags), //
B(JumpIfUndefined), U8(59), //
B(JumpIfNull), U8(57), //
B(ToObject), //
B(JumpIfUndefined), U8(56), //
B(JumpIfNull), U8(54), //
B(ToObject), //
B(JumpIfNull), U8(51), //
B(Star), R(1), //
B(ForInPrepare), R(2), R(3), R(4), //
B(ForInPrepare), R(2), //
B(LdaZero), //
B(Star), R(5), //
B(ForInDone), R(5), R(4), //
B(JumpIfTrue), U8(40), //
B(ForInNext), R(1), R(2), R(3), R(5), //
B(JumpIfTrue), U8(39), //
B(ForInNext), R(1), R(5), R(2), //
B(JumpIfUndefined), U8(27), //
B(Star), R(6), //
B(Ldar), R(0), //
......@@ -5401,7 +5401,7 @@ TEST(ForIn) {
B(Return), //
B(ForInStep), R(5), //
B(Star), R(5), //
B(Jump), U8(-41), //
B(Jump), U8(-40), //
B(LdaUndefined), //
B(Return), //
},
......
......@@ -351,6 +351,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
case interpreter::OperandType::kMaybeReg8:
case interpreter::OperandType::kReg8:
case interpreter::OperandType::kRegPair8:
case interpreter::OperandType::kRegTriple8:
EXPECT_THAT(m.BytecodeOperandReg(i),
m.IsBytecodeOperandSignExtended(offset));
break;
......
......@@ -209,9 +209,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.Throw()
.Bind(&after_throw);
builder.ForInPrepare(reg, reg, reg)
builder.ForInPrepare(reg)
.ForInDone(reg, reg)
.ForInNext(reg, reg, reg, reg)
.ForInNext(reg, reg, reg)
.ForInStep(reg);
// Wide constant pool loads
......
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