[turbofan] Remove special JSForInStep and JSForInDone.

These JavaScript operators were special hacks to ensure that we always
operate on Smis for the magic for-in index variable, but this never
really worked in the OSR case, because the OsrValue for the index
variable didn't have the proper information (that we have for the
JSForInPrepare in the non-OSR case).

Now that we have loop induction variable analysis and binary operation
hints, we can just use JSLessThan and JSAdd instead with appropriate
Smi hints, which handle the OSR case by inserting Smi checks (that are
always true). Thanks to OSR deconstruction and loop peeling these Smi
checks will be hoisted so they don't hurt the OSR case too much.

Drive-by-change: Rename the ForInDone bytecode to ForInContinue, since
we have to lower it to JSLessThan to get the loop induction variable
goodness.

R=epertoso@chromium.org
BUG=v8:5267

Review-Url: https://codereview.chromium.org/2289613002
Cr-Commit-Position: refs/heads/master@{#38968}
This commit is contained in:
bmeurer 2016-08-29 01:47:12 -07:00 committed by Commit bot
parent 57ce7d674c
commit 1915762cc8
30 changed files with 59 additions and 129 deletions

View File

@ -718,13 +718,14 @@ class ForInStatement final : public ForEachStatement {
ForInType for_in_type() const { return for_in_type_; }
void set_for_in_type(ForInType type) { for_in_type_ = type; }
static int num_ids() { return parent_num_ids() + 6; }
static int num_ids() { return parent_num_ids() + 7; }
BailoutId BodyId() const { return BailoutId(local_id(0)); }
BailoutId EnumId() const { return BailoutId(local_id(1)); }
BailoutId ToObjectId() const { return BailoutId(local_id(2)); }
BailoutId PrepareId() const { return BailoutId(local_id(3)); }
BailoutId FilterId() const { return BailoutId(local_id(4)); }
BailoutId AssignmentId() const { return BailoutId(local_id(5)); }
BailoutId IncrementId() const { return BailoutId(local_id(6)); }
BailoutId ContinueId() const { return EntryId(); }
BailoutId StackCheckId() const { return BodyId(); }

View File

@ -1392,9 +1392,14 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
Node* cache_type = environment()->Peek(3);
Node* object = environment()->Peek(4);
// Check loop termination condition.
Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length);
for_loop.BreakWhen(exit_cond);
// Check loop termination condition (we know that the {index} is always
// in Smi range, so we can just set the hint on the comparison below).
PrepareEagerCheckpoint(stmt->EntryId());
Node* exit_cond =
NewNode(javascript()->LessThan(CompareOperationHint::kSignedSmall),
index, cache_length);
PrepareFrameState(exit_cond, BailoutId::None());
for_loop.BreakUnless(exit_cond);
// Compute the next enumerated value.
Node* value = NewNode(javascript()->ForInNext(), object, cache_array,
@ -1422,9 +1427,13 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
test_value.End();
for_loop.EndBody();
// Increment counter and continue.
// Increment counter and continue (we know that the {index} is always
// in Smi range, so we can just set the hint on the increment below).
index = environment()->Peek(0);
index = NewNode(javascript()->ForInStep(), index);
PrepareEagerCheckpoint(stmt->IncrementId());
index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall),
index, jsgraph()->OneConstant());
PrepareFrameState(index, BailoutId::None());
environment()->Poke(0, index);
}
for_loop.EndLoop();

View File

@ -1546,13 +1546,15 @@ void BytecodeGraphBuilder::BuildForInPrepare() {
void BytecodeGraphBuilder::VisitForInPrepare() { BuildForInPrepare(); }
void BytecodeGraphBuilder::VisitForInDone() {
void BytecodeGraphBuilder::VisitForInContinue() {
FrameStateBeforeAndAfter states(this);
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* cache_length =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length);
Node* exit_cond =
NewNode(javascript()->LessThan(CompareOperationHint::kSignedSmall), index,
cache_length);
environment()->BindAccumulator(exit_cond, &states);
}
@ -1579,7 +1581,8 @@ void BytecodeGraphBuilder::VisitForInStep() {
FrameStateBeforeAndAfter states(this);
Node* index =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
index = NewNode(javascript()->ForInStep(), index);
index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall), index,
jsgraph()->OneConstant());
environment()->BindAccumulator(index, &states);
}

View File

@ -574,11 +574,6 @@ void JSGenericLowering::LowerJSCallRuntime(Node* node) {
}
void JSGenericLowering::LowerJSForInDone(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kForInDone);
}
void JSGenericLowering::LowerJSForInNext(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kForInNext);
}
@ -588,12 +583,6 @@ void JSGenericLowering::LowerJSForInPrepare(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kForInPrepare);
}
void JSGenericLowering::LowerJSForInStep(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kForInStep);
}
void JSGenericLowering::LowerJSLoadMessage(Node* node) {
ExternalReference message_address =
ExternalReference::address_of_pending_message_obj(isolate());

View File

@ -415,10 +415,8 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(HasProperty, Operator::kNoProperties, 2, 1) \
V(TypeOf, Operator::kPure, 1, 1) \
V(InstanceOf, Operator::kNoProperties, 2, 1) \
V(ForInDone, Operator::kPure, 2, 1) \
V(ForInNext, Operator::kNoProperties, 4, 1) \
V(ForInPrepare, Operator::kNoProperties, 1, 3) \
V(ForInStep, Operator::kPure, 1, 1) \
V(LoadMessage, Operator::kNoThrow, 0, 1) \
V(StoreMessage, Operator::kNoThrow, 1, 0) \
V(GeneratorRestoreContinuation, Operator::kNoThrow, 1, 1) \

View File

@ -465,10 +465,8 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* TypeOf();
const Operator* InstanceOf();
const Operator* ForInDone();
const Operator* ForInNext();
const Operator* ForInPrepare();
const Operator* ForInStep();
const Operator* LoadMessage();
const Operator* StoreMessage();

View File

@ -1765,14 +1765,6 @@ Reduction JSTypedLowering::ReduceJSCallFunction(Node* node) {
}
Reduction JSTypedLowering::ReduceJSForInDone(Node* node) {
DCHECK_EQ(IrOpcode::kJSForInDone, node->opcode());
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, machine()->Word32Equal());
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 0);
@ -1838,14 +1830,6 @@ Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSForInStep(Node* node) {
DCHECK_EQ(IrOpcode::kJSForInStep, node->opcode());
node->ReplaceInput(1, jsgraph()->Int32Constant(1));
NodeProperties::ChangeOp(node, machine()->Int32Add());
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
Node* generator = NodeProperties::GetValueInput(node, 0);
@ -1986,12 +1970,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSCallConstruct(node);
case IrOpcode::kJSCallFunction:
return ReduceJSCallFunction(node);
case IrOpcode::kJSForInDone:
return ReduceJSForInDone(node);
case IrOpcode::kJSForInNext:
return ReduceJSForInNext(node);
case IrOpcode::kJSForInStep:
return ReduceJSForInStep(node);
case IrOpcode::kJSGeneratorStore:
return ReduceJSGeneratorStore(node);
case IrOpcode::kJSGeneratorRestoreContinuation:
@ -2023,10 +2003,6 @@ CommonOperatorBuilder* JSTypedLowering::common() const {
return jsgraph()->common();
}
MachineOperatorBuilder* JSTypedLowering::machine() const {
return jsgraph()->machine();
}
SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
return jsgraph()->simplified();
}

View File

@ -22,7 +22,6 @@ namespace compiler {
class CommonOperatorBuilder;
class JSGraph;
class JSOperatorBuilder;
class MachineOperatorBuilder;
class SimplifiedOperatorBuilder;
class TypeCache;
@ -67,9 +66,7 @@ class JSTypedLowering final : public AdvancedReducer {
Reduction ReduceJSConvertReceiver(Node* node);
Reduction ReduceJSCallConstruct(Node* node);
Reduction ReduceJSCallFunction(Node* node);
Reduction ReduceJSForInDone(Node* node);
Reduction ReduceJSForInNext(Node* node);
Reduction ReduceJSForInStep(Node* node);
Reduction ReduceJSGeneratorStore(Node* node);
Reduction ReduceJSGeneratorRestoreContinuation(Node* node);
Reduction ReduceJSGeneratorRestoreRegister(Node* node);
@ -84,7 +81,6 @@ class JSTypedLowering final : public AdvancedReducer {
JSOperatorBuilder* javascript() const;
CommonOperatorBuilder* common() const;
SimplifiedOperatorBuilder* simplified() const;
MachineOperatorBuilder* machine() const;
CompilationDependencies* dependencies() const;
Flags flags() const { return flags_; }

View File

@ -161,8 +161,6 @@ bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) {
case Runtime::kCreateIterResultObject:
case Runtime::kDefineGetterPropertyUnchecked: // TODO(jarin): Is it safe?
case Runtime::kDefineSetterPropertyUnchecked: // TODO(jarin): Is it safe?
case Runtime::kForInDone:
case Runtime::kForInStep:
case Runtime::kGeneratorGetContinuation:
case Runtime::kGetSuperConstructor:
case Runtime::kIsFunction:

View File

@ -150,10 +150,8 @@
V(JSCallFunction) \
V(JSCallRuntime) \
V(JSConvertReceiver) \
V(JSForInDone) \
V(JSForInNext) \
V(JSForInPrepare) \
V(JSForInStep) \
V(JSLoadMessage) \
V(JSStoreMessage) \
V(JSGeneratorStore) \

View File

@ -1437,13 +1437,6 @@ Type* Typer::Visitor::TypeJSForInPrepare(Node* node) {
return Type::Tuple(cache_type, cache_array, cache_length, zone());
}
Type* Typer::Visitor::TypeJSForInDone(Node* node) { return Type::Boolean(); }
Type* Typer::Visitor::TypeJSForInStep(Node* node) {
STATIC_ASSERT(Map::EnumLengthBits::kMax <= FixedArray::kMaxLength);
return Type::Range(1, FixedArray::kMaxLength + 1, zone());
}
Type* Typer::Visitor::TypeJSLoadMessage(Node* node) { return Type::Any(); }

View File

@ -635,23 +635,10 @@ void Verifier::Visitor::Check(Node* node) {
CheckUpperIs(node, Type::Any());
break;
}
case IrOpcode::kJSForInDone: {
// TODO(bmeurer): OSR breaks this invariant, although the node is not user
// visible, so we know it is safe (fullcodegen has an unsigned smi there).
// CheckValueInputIs(node, 0, Type::UnsignedSmall());
break;
}
case IrOpcode::kJSForInNext: {
CheckUpperIs(node, Type::Union(Type::Name(), Type::Undefined(), zone));
break;
}
case IrOpcode::kJSForInStep: {
// TODO(bmeurer): OSR breaks this invariant, although the node is not user
// visible, so we know it is safe (fullcodegen has an unsigned smi there).
// CheckValueInputIs(node, 0, Type::UnsignedSmall());
CheckUpperIs(node, Type::UnsignedSmall());
break;
}
case IrOpcode::kJSLoadMessage:
case IrOpcode::kJSStoreMessage:

View File

@ -1131,6 +1131,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack.
__ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
__ pop(r0);
__ add(r0, r0, Operand(Smi::FromInt(1)));
__ push(r0);

View File

@ -1120,6 +1120,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for going to the next element by incrementing
// the index (smi) stored on top of the stack.
__ Bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
// TODO(all): We could use a callee saved register to avoid popping.
__ Pop(x0);
__ Add(x0, x0, Smi::FromInt(1));

View File

@ -1060,6 +1060,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for going to the next element by incrementing the
// index (smi) stored on top of the stack.
__ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
__ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
EmitBackEdgeBookkeeping(stmt, &loop);

View File

@ -1126,6 +1126,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack.
__ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
__ pop(a0);
__ Addu(a0, a0, Operand(Smi::FromInt(1)));
__ push(a0);

View File

@ -1127,6 +1127,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack.
__ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
__ pop(a0);
__ Daddu(a0, a0, Operand(Smi::FromInt(1)));
__ push(a0);

View File

@ -1086,6 +1086,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for going to the next element by incrementing the
// index (smi) stored on top of the stack.
__ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
__ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
EmitBackEdgeBookkeeping(stmt, &loop);

View File

@ -533,9 +533,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
Register cache_length) {
Output(Bytecode::kForInDone, RegisterOperand(index),
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInContinue(
Register index, Register cache_length) {
Output(Bytecode::kForInContinue, RegisterOperand(index),
RegisterOperand(cache_length));
return *this;
}

View File

@ -265,7 +265,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
// Complex flow control.
BytecodeArrayBuilder& ForInPrepare(Register receiver,
Register cache_info_triple);
BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length);
BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
Register cache_type_array_pair,
int feedback_slot);

View File

@ -1331,8 +1331,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// The loop
VisitIterationHeader(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->each());
builder()->ForInDone(index, cache_length);
loop_builder.BreakIfTrue();
builder()->ForInContinue(index, cache_length);
loop_builder.BreakIfFalse();
DCHECK(Register::AreContiguous(cache_type, cache_array));
FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
builder()->ForInNext(receiver, index, cache_type, feedback_index(slot));

View File

@ -255,7 +255,7 @@ bool Bytecodes::WritesBooleanToAccumulator(Bytecode bytecode) {
case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn:
case Bytecode::kForInDone:
case Bytecode::kForInContinue:
return true;
default:
return false;

View File

@ -269,7 +269,8 @@ namespace interpreter {
/* Complex flow control For..in */ \
V(ForInPrepare, AccumulatorUse::kNone, OperandType::kReg, \
OperandType::kRegOutTriple) \
V(ForInDone, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg) \
V(ForInContinue, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kReg) \
V(ForInNext, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kRegPair, OperandType::kIdx) \
V(ForInStep, AccumulatorUse::kWrite, OperandType::kReg) \

View File

@ -2260,10 +2260,10 @@ void Interpreter::DoForInNext(InterpreterAssembler* assembler) {
}
}
// ForInDone <index> <cache_length>
// ForInContinue <index> <cache_length>
//
// Returns true if the end of the enumerable properties has been reached.
void Interpreter::DoForInDone(InterpreterAssembler* assembler) {
// Returns false if the end of the enumerable properties has been reached.
void Interpreter::DoForInContinue(InterpreterAssembler* assembler) {
Node* index_reg = __ BytecodeOperandReg(0);
Node* index = __ LoadRegister(index_reg);
Node* cache_length_reg = __ BytecodeOperandReg(1);
@ -2274,12 +2274,12 @@ void Interpreter::DoForInDone(InterpreterAssembler* assembler) {
__ BranchIfWordEqual(index, cache_length, &if_true, &if_false);
__ Bind(&if_true);
{
__ SetAccumulator(__ BooleanConstant(true));
__ SetAccumulator(__ BooleanConstant(false));
__ Goto(&end);
}
__ Bind(&if_false);
{
__ SetAccumulator(__ BooleanConstant(false));
__ SetAccumulator(__ BooleanConstant(true));
__ Goto(&end);
}
__ Bind(&end);

View File

@ -140,17 +140,6 @@ RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) {
return MakeTriple(*cache_type, *cache_array, Smi::FromInt(cache_length));
}
RUNTIME_FUNCTION(Runtime_ForInDone) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_SMI_ARG_CHECKED(index, 0);
CONVERT_SMI_ARG_CHECKED(length, 1);
DCHECK_LE(0, index);
DCHECK_LE(index, length);
return isolate->heap()->ToBoolean(index == length);
}
RUNTIME_FUNCTION(Runtime_ForInHasProperty) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
@ -188,15 +177,5 @@ RUNTIME_FUNCTION(Runtime_ForInNext) {
HasEnumerableProperty(isolate, receiver, key));
}
RUNTIME_FUNCTION(Runtime_ForInStep) {
SealHandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_SMI_ARG_CHECKED(index, 0);
DCHECK_LE(0, index);
DCHECK_LT(index, Smi::kMaxValue);
return Smi::FromInt(index + 1);
}
} // namespace internal
} // namespace v8

View File

@ -204,12 +204,10 @@ namespace internal {
#define FOR_EACH_INTRINSIC_ERROR(F) F(ErrorToString, 1, 1)
#define FOR_EACH_INTRINSIC_FORIN(F) \
F(ForInDone, 2, 1) \
F(ForInEnumerate, 1, 1) \
F(ForInFilter, 2, 1) \
F(ForInHasProperty, 2, 1) \
F(ForInNext, 4, 1) \
F(ForInStep, 1, 1)
F(ForInNext, 4, 1)
#define FOR_EACH_INTRINSIC_INTERPRETER(F) \
F(InterpreterNewClosure, 2, 1) \

View File

@ -76,8 +76,8 @@ bytecodes: [
B(ForInPrepare), R(3), R(4),
B(LdaZero),
B(Star), R(7),
/* 63 S> */ B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(22),
/* 63 S> */ B(ForInContinue), R(7), R(6),
B(JumpIfFalse), U8(22),
B(ForInNext), R(3), R(7), R(4), U8(1),
B(JumpIfUndefined), U8(9),
B(Star), R(1),
@ -116,8 +116,8 @@ bytecodes: [
B(ForInPrepare), R(3), R(4),
B(LdaZero),
B(Star), R(7),
/* 54 S> */ B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(30),
/* 54 S> */ B(ForInContinue), R(7), R(6),
B(JumpIfFalse), U8(30),
B(ForInNext), R(3), R(7), R(4), U8(2),
B(JumpIfUndefined), U8(17),
B(Star), R(1),
@ -161,8 +161,8 @@ bytecodes: [
B(ForInPrepare), R(1), R(2),
B(LdaZero),
B(Star), R(5),
/* 68 S> */ B(ForInDone), R(5), R(4),
B(JumpIfTrue), U8(50),
/* 68 S> */ B(ForInContinue), R(5), R(4),
B(JumpIfFalse), U8(50),
B(ForInNext), R(1), R(5), R(2), U8(9),
B(JumpIfUndefined), U8(37),
B(Star), R(6),
@ -213,8 +213,8 @@ bytecodes: [
B(ForInPrepare), R(1), R(2),
B(LdaZero),
B(Star), R(5),
/* 65 S> */ B(ForInDone), R(5), R(4),
B(JumpIfTrue), U8(33),
/* 65 S> */ B(ForInContinue), R(5), R(4),
B(JumpIfFalse), U8(33),
B(ForInNext), R(1), R(5), R(2), U8(7),
B(JumpIfUndefined), U8(20),
B(Star), R(6),

View File

@ -1101,8 +1101,8 @@ bytecodes: [
B(Wide), B(ForInPrepare), R16(157), R16(158),
B(LdaZero),
B(Wide), B(Star), R16(161),
/* 1526 S> */ B(Wide), B(ForInDone), R16(161), R16(160),
B(JumpIfTrue), U8(44),
/* 1526 S> */ B(Wide), B(ForInContinue), R16(161), R16(160),
B(JumpIfFalse), U8(44),
B(Wide), B(ForInNext), R16(157), R16(161), R16(158), U16(2),
B(JumpIfUndefined), U8(22),
B(Wide), B(Star), R16(128),

View File

@ -273,11 +273,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.ReThrow().Bind(&after_rethrow);
builder.ForInPrepare(reg, reg)
.ForInDone(reg, reg)
.ForInContinue(reg, reg)
.ForInNext(reg, reg, reg, 1)
.ForInStep(reg);
builder.ForInPrepare(reg, wide)
.ForInDone(reg, other)
.ForInContinue(reg, other)
.ForInNext(wide, wide, wide, 1024)
.ForInStep(reg);

View File

@ -167,8 +167,8 @@ TEST_F(BytecodeArrayWriterUnittest, ComplexExample) {
/* 11 */ B(ForInPrepare), R8(3), R8(4),
/* 14 */ B(LdaZero),
/* 15 */ B(Star), R8(7),
/* 17 63 S> */ B(ForInDone), R8(7), R8(6),
/* 20 */ B(JumpIfTrue), U8(23),
/* 17 63 S> */ B(ForInContinue), R8(7), R8(6),
/* 20 */ B(JumpIfFalse), U8(23),
/* 22 */ B(ForInNext), R8(3), R8(7), R8(4), U8(1),
/* 27 */ B(JumpIfUndefined), U8(10),
/* 29 */ B(Star), R8(0),
@ -207,9 +207,9 @@ TEST_F(BytecodeArrayWriterUnittest, ComplexExample) {
Write(Bytecode::kStar, R(7));
CHECK_EQ(max_register_count(), 8);
writer()->BindLabel(&back_jump);
Write(Bytecode::kForInDone, R(7), R(6), {63, true});
Write(Bytecode::kForInContinue, R(7), R(6), {63, true});
CHECK_EQ(max_register_count(), 8);
WriteJump(Bytecode::kJumpIfTrue, &jump_end_3);
WriteJump(Bytecode::kJumpIfFalse, &jump_end_3);
Write(Bytecode::kForInNext, R(3), R(7), R(4), U8(1));
WriteJump(Bytecode::kJumpIfUndefined, &jump_for_in);
Write(Bytecode::kStar, R(0));