diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index 8a33edd8b8..07236118a0 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -10,6 +10,7 @@ #include "src/compiler/compiler-source-position-table.h" #include "src/compiler/linkage.h" #include "src/compiler/operator-properties.h" +#include "src/compiler/simplified-operator.h" #include "src/interpreter/bytecodes.h" #include "src/objects-inl.h" @@ -1643,6 +1644,13 @@ void BytecodeGraphBuilder::VisitTestInstanceOf() { BuildCompareOp(javascript()->InstanceOf()); } +void BytecodeGraphBuilder::VisitTestUndetectable() { + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + Node* node = NewNode(jsgraph()->simplified()->ObjectIsUndetectable(), object); + environment()->BindAccumulator(node); +} + void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) { PrepareEagerCheckpoint(); Node* value = NewNode(js_op, environment()->LookupAccumulator()); diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 5565e01f54..a2ffb07d9a 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -588,6 +588,7 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) const AstRawString* prototype_string = ast_value_factory->prototype_string(); ast_value_factory->Internalize(info->isolate()); prototype_string_ = prototype_string->string(); + undefined_string_ = ast_value_factory->undefined_string(); } Handle BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { @@ -1831,8 +1832,15 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, break; } case VariableLocation::UNALLOCATED: { - builder()->LoadGlobal(variable->name(), feedback_index(slot), - typeof_mode); + // The global identifier "undefined" is immutable. Everything + // else could be reassigned. For performance, we do a pointer comparison + // rather than checking if the raw_name is really "undefined". + if (variable->raw_name() == undefined_string()) { + builder()->LoadUndefined(); + } else { + builder()->LoadGlobal(variable->name(), feedback_index(slot), + typeof_mode); + } break; } case VariableLocation::CONTEXT: { diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h index 7b49021b38..96405f6be1 100644 --- a/src/interpreter/bytecode-generator.h +++ b/src/interpreter/bytecode-generator.h @@ -195,6 +195,7 @@ class BytecodeGenerator final : public AstVisitor { Handle home_object_symbol() const { return home_object_symbol_; } Handle prototype_string() const { return prototype_string_; } Handle empty_fixed_array() const { return empty_fixed_array_; } + const AstRawString* undefined_string() const { return undefined_string_; } Zone* zone_; BytecodeArrayBuilder* builder_; @@ -218,6 +219,7 @@ class BytecodeGenerator final : public AstVisitor { Handle home_object_symbol_; Handle prototype_string_; Handle empty_fixed_array_; + const AstRawString* undefined_string_; }; } // namespace interpreter diff --git a/src/interpreter/bytecode-peephole-optimizer.cc b/src/interpreter/bytecode-peephole-optimizer.cc index 40552943f7..dfc40a2c19 100644 --- a/src/interpreter/bytecode-peephole-optimizer.cc +++ b/src/interpreter/bytecode-peephole-optimizer.cc @@ -138,6 +138,17 @@ void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, } } +void TransformEqualityWithNullOrUndefinedToTestUndetectable( + BytecodeNode* const last, BytecodeNode* const current) { + DCHECK((last->bytecode() == Bytecode::kLdaNull) || + (last->bytecode() == Bytecode::kLdaUndefined)); + DCHECK_EQ(current->bytecode(), Bytecode::kTestEqual); + current->set_bytecode(Bytecode::kTestUndetectable, current->operand(0)); + if (last->source_info().is_valid()) { + current->set_source_info(last->source_info()); + } +} + } // namespace void BytecodePeepholeOptimizer::DefaultAction( @@ -251,6 +262,16 @@ void BytecodePeepholeOptimizer:: } } +void BytecodePeepholeOptimizer:: + TransformEqualityWithNullOrUndefinedToTestUndetectableAction( + BytecodeNode* const node, const PeepholeActionAndData* action_data) { + DCHECK(LastIsValid()); + DCHECK(!Bytecodes::IsJump(node->bytecode())); + // Fused last and current into current. + TransformEqualityWithNullOrUndefinedToTestUndetectable(last(), node); + SetLast(node); +} + void BytecodePeepholeOptimizer::DefaultJumpAction( BytecodeNode* const node, const PeepholeActionAndData* action_data) { DCHECK(LastIsValid()); diff --git a/src/interpreter/bytecode-peephole-table.h b/src/interpreter/bytecode-peephole-table.h index 1790f5a109..bcbf954a77 100644 --- a/src/interpreter/bytecode-peephole-table.h +++ b/src/interpreter/bytecode-peephole-table.h @@ -11,16 +11,17 @@ namespace v8 { namespace internal { namespace interpreter { -#define PEEPHOLE_NON_JUMP_ACTION_LIST(V) \ - V(DefaultAction) \ - V(UpdateLastAction) \ - V(UpdateLastIfSourceInfoPresentAction) \ - V(ElideCurrentAction) \ - V(ElideCurrentIfOperand0MatchesAction) \ - V(ElideLastAction) \ - V(ChangeBytecodeAction) \ - V(TransformLdaSmiBinaryOpToBinaryOpWithSmiAction) \ - V(TransformLdaZeroBinaryOpToBinaryOpWithZeroAction) +#define PEEPHOLE_NON_JUMP_ACTION_LIST(V) \ + V(DefaultAction) \ + V(UpdateLastAction) \ + V(UpdateLastIfSourceInfoPresentAction) \ + V(ElideCurrentAction) \ + V(ElideCurrentIfOperand0MatchesAction) \ + V(ElideLastAction) \ + V(ChangeBytecodeAction) \ + V(TransformLdaSmiBinaryOpToBinaryOpWithSmiAction) \ + V(TransformLdaZeroBinaryOpToBinaryOpWithZeroAction) \ + V(TransformEqualityWithNullOrUndefinedToTestUndetectableAction) #define PEEPHOLE_JUMP_ACTION_LIST(V) \ V(DefaultJumpAction) \ diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index b691a927f7..fa2c828e01 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -183,6 +183,9 @@ namespace interpreter { V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \ V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \ \ + /* TestEqual with Null or Undefined */ \ + V(TestUndetectable, AccumulatorUse::kWrite, OperandType::kReg) \ + \ /* Cast operators */ \ V(ToName, AccumulatorUse::kRead, OperandType::kRegOut) \ V(ToNumber, AccumulatorUse::kRead, OperandType::kRegOut) \ @@ -483,6 +486,7 @@ class V8_EXPORT_PRIVATE Bytecodes final { case Bytecode::kTestGreaterThanOrEqual: case Bytecode::kTestInstanceOf: case Bytecode::kTestIn: + case Bytecode::kTestUndetectable: case Bytecode::kForInContinue: return true; default: diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 3e7af6e90d..5257805752 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -1918,6 +1918,38 @@ void Interpreter::DoTestInstanceOf(InterpreterAssembler* assembler) { DoCompareOp(Token::INSTANCEOF, assembler); } +// TestUndetectable +// +// Test if the value in the register equals to Null/Undefined. This is +// done by checking undetectable bit on the map of the object. +void Interpreter::DoTestUndetectable(InterpreterAssembler* assembler) { + Node* reg_index = __ BytecodeOperandReg(0); + Node* object = __ LoadRegister(reg_index); + + Label not_equal(assembler), end(assembler); + // If the object is an Smi then return false. + __ GotoIf(__ TaggedIsSmi(object), ¬_equal); + + // If it is a HeapObject, load the map and check for undetectable bit. + Node* map = __ LoadMap(object); + Node* map_bitfield = __ LoadMapBitField(map); + Node* map_undetectable = + __ Word32And(map_bitfield, __ Int32Constant(1 << Map::kIsUndetectable)); + __ GotoIf(__ Word32Equal(map_undetectable, __ Int32Constant(0)), ¬_equal); + + __ SetAccumulator(__ BooleanConstant(true)); + __ Goto(&end); + + __ Bind(¬_equal); + { + __ SetAccumulator(__ BooleanConstant(false)); + __ Goto(&end); + } + + __ Bind(&end); + __ Dispatch(); +} + // Jump // // Jump by number of bytes represented by the immediate operand |imm|. diff --git a/src/interpreter/mkpeephole.cc b/src/interpreter/mkpeephole.cc index 62d3a77e02..08e0301625 100644 --- a/src/interpreter/mkpeephole.cc +++ b/src/interpreter/mkpeephole.cc @@ -192,6 +192,19 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData( } } + // Fuse LdaNull/LdaUndefined followed by a equality comparison with test + // undetectable. Testing undetectable is a simple check on the map which is + // more efficient than the full comparison operation. + // Note: StrictEquals cannot use this, they need to compare it with the + // Null/undefined map. + if (last == Bytecode::kLdaNull || last == Bytecode::kLdaUndefined) { + if (current == Bytecode::kTestEqual) { + return {PeepholeAction:: + kTransformEqualityWithNullOrUndefinedToTestUndetectableAction, + Bytecode::kIllegal}; + } + } + // If there is no last bytecode to optimize against, store the incoming // bytecode or for jumps emit incoming bytecode immediately. if (last == Bytecode::kIllegal) { diff --git a/test/cctest/interpreter/bytecode_expectations/ForOf.golden b/test/cctest/interpreter/bytecode_expectations/ForOf.golden index 21abc69cae..698de734ac 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForOf.golden @@ -11,7 +11,7 @@ snippet: " " frame size: 15 parameter count: 1 -bytecode array length: 268 +bytecode array length: 266 bytecodes: [ /* 30 E> */ B(StackCheck), B(LdaZero), @@ -71,11 +71,10 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(4), U8(15), - B(JumpIfTrue), U8(113), + B(JumpIfTrue), U8(111), B(LdaNamedProperty), R(2), U8(7), U8(16), B(Star), R(6), - B(LdaNull), - B(TestEqual), R(6), U8(18), + B(TestUndetectable), R(6), B(JumpIfFalse), U8(4), B(Jump), U8(99), B(LdaSmi), U8(1), @@ -144,7 +143,7 @@ constant pool: [ handlers: [ [7, 120, 126], [10, 84, 86], - [195, 205, 207], + [193, 203, 205], ] --- @@ -154,7 +153,7 @@ snippet: " " frame size: 16 parameter count: 1 -bytecode array length: 279 +bytecode array length: 277 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(LdaConstant), U8(0), @@ -215,11 +214,10 @@ bytecodes: [ B(Star), R(12), B(LdaZero), B(TestEqualStrict), R(5), U8(15), - B(JumpIfTrue), U8(113), + B(JumpIfTrue), U8(111), B(LdaNamedProperty), R(3), U8(7), U8(16), B(Star), R(7), - B(LdaNull), - B(TestEqual), R(7), U8(18), + B(TestUndetectable), R(7), B(JumpIfFalse), U8(4), B(Jump), U8(99), B(LdaSmi), U8(1), @@ -293,7 +291,7 @@ constant pool: [ handlers: [ [11, 120, 126], [14, 84, 86], - [196, 206, 208], + [194, 204, 206], ] --- @@ -305,7 +303,7 @@ snippet: " " frame size: 15 parameter count: 1 -bytecode array length: 286 +bytecode array length: 284 bytecodes: [ /* 30 E> */ B(StackCheck), B(LdaZero), @@ -373,11 +371,10 @@ bytecodes: [ B(Star), R(11), B(LdaZero), B(TestEqualStrict), R(4), U8(17), - B(JumpIfTrue), U8(113), + B(JumpIfTrue), U8(111), B(LdaNamedProperty), R(2), U8(7), U8(18), B(Star), R(6), - B(LdaNull), - B(TestEqual), R(6), U8(20), + B(TestUndetectable), R(6), B(JumpIfFalse), U8(4), B(Jump), U8(99), B(LdaSmi), U8(1), @@ -446,7 +443,7 @@ constant pool: [ handlers: [ [7, 138, 144], [10, 102, 104], - [213, 223, 225], + [211, 221, 223], ] --- @@ -456,7 +453,7 @@ snippet: " " frame size: 14 parameter count: 1 -bytecode array length: 293 +bytecode array length: 291 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(8), @@ -521,11 +518,10 @@ bytecodes: [ B(Star), R(10), B(LdaZero), B(TestEqualStrict), R(3), U8(19), - B(JumpIfTrue), U8(113), + B(JumpIfTrue), U8(111), B(LdaNamedProperty), R(1), U8(9), U8(20), B(Star), R(5), - B(LdaNull), - B(TestEqual), R(5), U8(22), + B(TestUndetectable), R(5), B(JumpIfFalse), U8(4), B(Jump), U8(99), B(LdaSmi), U8(1), @@ -601,6 +597,6 @@ constant pool: [ handlers: [ [15, 134, 140], [18, 98, 100], - [210, 220, 222], + [208, 218, 220], ] diff --git a/test/cctest/interpreter/bytecode_expectations/GenerateTestUndetectable.golden b/test/cctest/interpreter/bytecode_expectations/GenerateTestUndetectable.golden new file mode 100644 index 0000000000..51c9c3ab4c --- /dev/null +++ b/test/cctest/interpreter/bytecode_expectations/GenerateTestUndetectable.golden @@ -0,0 +1,123 @@ +# +# Autogenerated by generate-bytecode-expectations. +# + +--- +wrap: yes + +--- +snippet: " + var obj_a = {val:1}; + var b = 10; + if (obj_a == null) { b = 20;} + return b; +" +frame size: 3 +parameter count: 1 +bytecode array length: 24 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 46 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(2), + B(Mov), R(2), R(0), + /* 63 S> */ B(LdaSmi), U8(10), + B(Star), R(1), + /* 67 S> */ B(TestUndetectable), R(0), + B(JumpIfFalse), U8(6), + /* 88 S> */ B(LdaSmi), U8(20), + B(Star), R(1), + /* 97 S> */ B(Ldar), R(1), + /* 107 S> */ B(Return), +] +constant pool: [ + FIXED_ARRAY_TYPE, +] +handlers: [ +] + +--- +snippet: " + var obj_a = {val:1}; + var b = 10; + if (obj_a == undefined) { b = 20;} + return b; +" +frame size: 3 +parameter count: 1 +bytecode array length: 24 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 46 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(2), + B(Mov), R(2), R(0), + /* 63 S> */ B(LdaSmi), U8(10), + B(Star), R(1), + /* 67 S> */ B(TestUndetectable), R(0), + B(JumpIfFalse), U8(6), + /* 93 S> */ B(LdaSmi), U8(20), + B(Star), R(1), + /* 102 S> */ B(Ldar), R(1), + /* 112 S> */ B(Return), +] +constant pool: [ + FIXED_ARRAY_TYPE, +] +handlers: [ +] + +--- +snippet: " + var obj_a = {val:1}; + var b = 10; + if (obj_a != null) { b = 20;} + return b; +" +frame size: 3 +parameter count: 1 +bytecode array length: 24 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 46 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(2), + B(Mov), R(2), R(0), + /* 63 S> */ B(LdaSmi), U8(10), + B(Star), R(1), + /* 67 S> */ B(TestUndetectable), R(0), + B(JumpIfTrue), U8(6), + /* 88 S> */ B(LdaSmi), U8(20), + B(Star), R(1), + /* 97 S> */ B(Ldar), R(1), + /* 107 S> */ B(Return), +] +constant pool: [ + FIXED_ARRAY_TYPE, +] +handlers: [ +] + +--- +snippet: " + var obj_a = {val:1}; + var b = 10; + if (obj_a != undefined) { b = 20;} + return b; +" +frame size: 3 +parameter count: 1 +bytecode array length: 24 +bytecodes: [ + /* 30 E> */ B(StackCheck), + /* 46 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(2), + B(Mov), R(2), R(0), + /* 63 S> */ B(LdaSmi), U8(10), + B(Star), R(1), + /* 67 S> */ B(TestUndetectable), R(0), + B(JumpIfTrue), U8(6), + /* 93 S> */ B(LdaSmi), U8(20), + B(Star), R(1), + /* 102 S> */ B(Ldar), R(1), + /* 112 S> */ B(Return), +] +constant pool: [ + FIXED_ARRAY_TYPE, +] +handlers: [ +] + diff --git a/test/cctest/interpreter/bytecode_expectations/Generators.golden b/test/cctest/interpreter/bytecode_expectations/Generators.golden index 1f379c0306..f7e392ee8d 100644 --- a/test/cctest/interpreter/bytecode_expectations/Generators.golden +++ b/test/cctest/interpreter/bytecode_expectations/Generators.golden @@ -277,7 +277,7 @@ snippet: " " frame size: 17 parameter count: 1 -bytecode array length: 771 +bytecode array length: 769 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(28), @@ -475,8 +475,7 @@ bytecodes: [ B(StaContextSlot), R(1), U8(11), U8(0), B(LdaContextSlot), R(1), U8(11), U8(0), B(Star), R(10), - B(LdaNull), - B(TestEqual), R(10), U8(18), + B(TestUndetectable), R(10), B(JumpIfFalse), U8(4), B(JumpConstant), U8(16), B(LdaContextSlot), R(1), U8(9), U8(0), @@ -620,13 +619,13 @@ constant pool: [ ONE_BYTE_INTERNALIZED_STRING_TYPE [""], FIXED_ARRAY_TYPE, Smi [133], - Smi [161], - Smi [581], + Smi [159], + Smi [579], ] handlers: [ - [46, 690, 696], + [46, 688, 694], [143, 438, 444], [146, 394, 396], - [542, 558, 560], + [540, 556, 558], ] diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc index b583b331fd..c5e6b3a217 100644 --- a/test/cctest/interpreter/test-bytecode-generator.cc +++ b/test/cctest/interpreter/test-bytecode-generator.cc @@ -1742,6 +1742,31 @@ TEST(RemoveRedundantLdar) { LoadGolden("RemoveRedundantLdar.golden"))); } +TEST(GenerateTestUndetectable) { + InitializedIgnitionHandleScope scope; + BytecodeExpectationsPrinter printer(CcTest::isolate()); + const char* snippets[] = { + "var obj_a = {val:1};\n" + "var b = 10;\n" + "if (obj_a == null) { b = 20;}\n" + "return b;\n", + "var obj_a = {val:1};\n" + "var b = 10;\n" + "if (obj_a == undefined) { b = 20;}\n" + "return b;\n", + "var obj_a = {val:1};\n" + "var b = 10;\n" + "if (obj_a != null) { b = 20;}\n" + "return b;\n", + "var obj_a = {val:1};\n" + "var b = 10;\n" + "if (obj_a != undefined) { b = 20;}\n" + "return b;\n"}; + + CHECK(CompareTexts(BuildActual(printer, snippets), + LoadGolden("GenerateTestUndetectable.golden"))); +} + TEST(AssignmentsInBinaryExpression) { InitializedIgnitionHandleScope scope; BytecodeExpectationsPrinter printer(CcTest::isolate()); diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc index d7051d3b80..4980fac725 100644 --- a/test/cctest/test-serialize.cc +++ b/test/cctest/test-serialize.cc @@ -1075,7 +1075,7 @@ TEST(CodeSerializerLargeCodeObject) { Vector source = ConstructSource(STATIC_CHAR_VECTOR("var j=1; if (j == 0) {"), STATIC_CHAR_VECTOR("for (let i of Object.prototype);"), - STATIC_CHAR_VECTOR("} j=7; j"), 1000); + STATIC_CHAR_VECTOR("} j=7; j"), 1050); Handle source_str = isolate->factory()->NewStringFromOneByte(source).ToHandleChecked(); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 3a75fc0f02..a807971513 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -195,6 +195,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CompareOperation(Token::Value::INSTANCEOF, reg, 8) .CompareOperation(Token::Value::IN, reg, 9); + // Emit peephole optimizations of equality with Null or Undefined. + builder.LoadUndefined() + .CompareOperation(Token::Value::EQ, reg, 1) + .LoadNull() + .CompareOperation(Token::Value::EQ, reg, 1); + // Emit conversion operator invocations. builder.ConvertAccumulatorToNumber(reg) .ConvertAccumulatorToObject(reg) @@ -398,6 +404,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { scorecard[Bytecodes::ToByte(Bytecode::kBitwiseOrSmi)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kShiftLeftSmi)] = 1; scorecard[Bytecodes::ToByte(Bytecode::kShiftRightSmi)] = 1; + scorecard[Bytecodes::ToByte(Bytecode::kTestUndetectable)] = 1; } // Check return occurs at the end and only once in the BytecodeArray. diff --git a/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc b/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc index d1c570d421..70c50b5e10 100644 --- a/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc +++ b/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc @@ -403,6 +403,25 @@ TEST_F(BytecodePeepholeOptimizerTest, MergeLdaZeroWithBinaryOp) { } } +TEST_F(BytecodePeepholeOptimizerTest, MergeLdaNullOrUndefinedWithCompareOp) { + Bytecode first_bytecodes[] = {Bytecode::kLdaUndefined, Bytecode::kLdaNull}; + + for (auto first_bytecode : first_bytecodes) { + uint32_t reg_operand = Register(0).ToOperand(); + uint32_t idx_operand = 1; + BytecodeNode first(first_bytecode); + BytecodeNode second(Bytecode::kTestEqual, reg_operand, idx_operand); + optimizer()->Write(&first); + optimizer()->Write(&second); + Flush(); + CHECK_EQ(write_count(), 1); + CHECK_EQ(last_written().bytecode(), Bytecode::kTestUndetectable); + CHECK_EQ(last_written().operand_count(), 1); + CHECK_EQ(last_written().operand(0), reg_operand); + Reset(); + } +} + } // namespace interpreter } // namespace internal } // namespace v8