Commit 0cb8a1b7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[interpreter] Properly collect for-in slow mode feedback.

Similar to fullcodegen, Ignition now also marks a for-in statement as
slow (via the TypeFeedbackVector) when we have to call %ForInFilter,
i.e. we either have no enumeration cache or the receiver map changes
during an iteration of the for-in map.

R=mstarzinger@chromium.org
BUG=v8:3650
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#34391}
parent 653cdb44
...@@ -192,6 +192,16 @@ Node* CodeStubAssembler::LoadFixedArrayElementConstantIndex(Node* object, ...@@ -192,6 +192,16 @@ Node* CodeStubAssembler::LoadFixedArrayElementConstantIndex(Node* object,
return raw_assembler_->Load(MachineType::AnyTagged(), object, offset); return raw_assembler_->Load(MachineType::AnyTagged(), object, offset);
} }
Node* CodeStubAssembler::StoreFixedArrayElementNoWriteBarrier(Node* object,
Node* index,
Node* value) {
Node* offset =
IntPtrAdd(WordShl(index, IntPtrConstant(kPointerSizeLog2)),
IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag));
return StoreNoWriteBarrier(MachineRepresentation::kTagged, object, offset,
value);
}
Node* CodeStubAssembler::LoadRoot(Heap::RootListIndex root_index) { Node* CodeStubAssembler::LoadRoot(Heap::RootListIndex root_index) {
if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) { if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
Handle<Object> root = isolate()->heap()->root_handle(root_index); Handle<Object> root = isolate()->heap()->root_handle(root_index);
......
...@@ -221,6 +221,10 @@ class CodeStubAssembler { ...@@ -221,6 +221,10 @@ class CodeStubAssembler {
int additional_offset = 0); int additional_offset = 0);
Node* LoadFixedArrayElementConstantIndex(Node* object, int index); Node* LoadFixedArrayElementConstantIndex(Node* object, int index);
// Store an array element to a FixedArray.
Node* StoreFixedArrayElementNoWriteBarrier(Node* object, Node* index,
Node* value);
protected: protected:
// Protected helpers which delegate to RawMachineAssembler. // Protected helpers which delegate to RawMachineAssembler.
Graph* graph(); Graph* graph();
......
...@@ -996,17 +996,21 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index, ...@@ -996,17 +996,21 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
Register receiver, Register index, Register cache_type_array_pair) { Register receiver, Register index, Register cache_type_array_pair,
int feedback_slot) {
if (FitsInReg8Operand(receiver) && FitsInReg8Operand(index) && if (FitsInReg8Operand(receiver) && FitsInReg8Operand(index) &&
FitsInReg8Operand(cache_type_array_pair)) { FitsInReg8Operand(cache_type_array_pair) &&
FitsInIdx8Operand(feedback_slot)) {
Output(Bytecode::kForInNext, receiver.ToRawOperand(), index.ToRawOperand(), Output(Bytecode::kForInNext, receiver.ToRawOperand(), index.ToRawOperand(),
cache_type_array_pair.ToRawOperand()); cache_type_array_pair.ToRawOperand(),
static_cast<uint8_t>(feedback_slot));
} else if (FitsInReg16Operand(receiver) && FitsInReg16Operand(index) && } else if (FitsInReg16Operand(receiver) && FitsInReg16Operand(index) &&
FitsInReg16Operand(cache_type_array_pair)) { FitsInReg16Operand(cache_type_array_pair) &&
FitsInIdx16Operand(feedback_slot)) {
Output(Bytecode::kForInNextWide, receiver.ToRawOperand(), Output(Bytecode::kForInNextWide, receiver.ToRawOperand(),
index.ToRawOperand(), cache_type_array_pair.ToRawOperand()); index.ToRawOperand(), cache_type_array_pair.ToRawOperand(),
static_cast<uint16_t>(feedback_slot));
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
......
...@@ -246,7 +246,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -246,7 +246,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple); BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple);
BytecodeArrayBuilder& ForInDone(Register index, Register cache_length); BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
BytecodeArrayBuilder& ForInNext(Register receiver, Register index, BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
Register cache_type_array_pair); Register cache_type_array_pair,
int feedback_slot);
BytecodeArrayBuilder& ForInStep(Register index); BytecodeArrayBuilder& ForInStep(Register index);
// Exception handling. // Exception handling.
......
...@@ -1129,7 +1129,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { ...@@ -1129,7 +1129,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->ForInDone(index, cache_length); builder()->ForInDone(index, cache_length);
loop_builder.BreakIfTrue(); loop_builder.BreakIfTrue();
DCHECK(Register::AreContiguous(cache_type, cache_array)); DCHECK(Register::AreContiguous(cache_type, cache_array));
builder()->ForInNext(receiver, index, cache_type); FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
builder()->ForInNext(receiver, index, cache_type, feedback_index(slot));
loop_builder.ContinueIfUndefined(); loop_builder.ContinueIfUndefined();
VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
VisitIterationBody(stmt, &loop_builder); VisitIterationBody(stmt, &loop_builder);
......
...@@ -265,9 +265,10 @@ namespace interpreter { ...@@ -265,9 +265,10 @@ namespace interpreter {
V(ForInPrepare, OperandType::kRegOutTriple8) \ V(ForInPrepare, OperandType::kRegOutTriple8) \
V(ForInPrepareWide, OperandType::kRegOutTriple16) \ V(ForInPrepareWide, OperandType::kRegOutTriple16) \
V(ForInDone, OperandType::kReg8, OperandType::kReg8) \ V(ForInDone, OperandType::kReg8, OperandType::kReg8) \
V(ForInNext, OperandType::kReg8, OperandType::kReg8, OperandType::kRegPair8) \ V(ForInNext, OperandType::kReg8, OperandType::kReg8, OperandType::kRegPair8, \
OperandType::kIdx8) \
V(ForInNextWide, OperandType::kReg16, OperandType::kReg16, \ V(ForInNextWide, OperandType::kReg16, OperandType::kReg16, \
OperandType::kRegPair16) \ OperandType::kRegPair16, OperandType::kIdx16) \
V(ForInStep, OperandType::kReg8) \ V(ForInStep, OperandType::kReg8) \
\ \
/* Perform a stack guard check */ \ /* Perform a stack guard check */ \
......
...@@ -1830,11 +1830,38 @@ void Interpreter::DoForInNext(InterpreterAssembler* assembler) { ...@@ -1830,11 +1830,38 @@ void Interpreter::DoForInNext(InterpreterAssembler* assembler) {
Node* cache_type = __ LoadRegister(cache_type_reg); Node* cache_type = __ LoadRegister(cache_type_reg);
Node* cache_array_reg = __ NextRegister(cache_type_reg); Node* cache_array_reg = __ NextRegister(cache_type_reg);
Node* cache_array = __ LoadRegister(cache_array_reg); Node* cache_array = __ LoadRegister(cache_array_reg);
Node* context = __ GetContext();
Node* result = __ CallRuntime(Runtime::kForInNext, context, receiver, // Load the next key from the enumeration array.
cache_array, cache_type, index); Node* key = __ LoadFixedArrayElementSmiIndex(cache_array, index);
__ SetAccumulator(result);
__ Dispatch(); // Check if we can use the for-in fast path potentially using the enum cache.
InterpreterAssembler::Label if_fast(assembler), if_slow(assembler);
Node* receiver_map = __ LoadObjectField(receiver, HeapObject::kMapOffset);
Node* condition = __ WordEqual(receiver_map, cache_type);
__ Branch(condition, &if_fast, &if_slow);
__ Bind(&if_fast);
{
// Enum cache in use for {receiver}, the {key} is definitely valid.
__ SetAccumulator(key);
__ Dispatch();
}
__ Bind(&if_slow);
{
// Record the fact that we hit the for-in slow path.
Node* vector_index = __ BytecodeOperandIdx(3);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* megamorphic_sentinel =
__ HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate_));
__ StoreFixedArrayElementNoWriteBarrier(type_feedback_vector, vector_index,
megamorphic_sentinel);
// Need to filter the {key} for the {receiver}.
Node* context = __ GetContext();
Node* result =
__ CallRuntime(Runtime::kForInFilter, context, receiver, key);
__ SetAccumulator(result);
__ Dispatch();
}
} }
......
...@@ -133,23 +133,19 @@ void TypeFeedbackVector::ComputeCounts(int* with_type_info, int* generic) { ...@@ -133,23 +133,19 @@ void TypeFeedbackVector::ComputeCounts(int* with_type_info, int* generic) {
*generic = gen; *generic = gen;
} }
Handle<Symbol> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
Handle<Object> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
return isolate->factory()->uninitialized_symbol(); return isolate->factory()->uninitialized_symbol();
} }
Handle<Symbol> TypeFeedbackVector::MegamorphicSentinel(Isolate* isolate) {
Handle<Object> TypeFeedbackVector::MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->megamorphic_symbol(); return isolate->factory()->megamorphic_symbol();
} }
Handle<Symbol> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
Handle<Object> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
return isolate->factory()->premonomorphic_symbol(); return isolate->factory()->premonomorphic_symbol();
} }
Symbol* TypeFeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
Object* TypeFeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
return isolate->heap()->uninitialized_symbol(); return isolate->heap()->uninitialized_symbol();
} }
......
...@@ -231,17 +231,17 @@ class TypeFeedbackVector : public FixedArray { ...@@ -231,17 +231,17 @@ class TypeFeedbackVector : public FixedArray {
void ClearKeyedStoreICs(SharedFunctionInfo* shared); void ClearKeyedStoreICs(SharedFunctionInfo* shared);
// The object that indicates an uninitialized cache. // The object that indicates an uninitialized cache.
static inline Handle<Object> UninitializedSentinel(Isolate* isolate); static inline Handle<Symbol> UninitializedSentinel(Isolate* isolate);
// The object that indicates a megamorphic state. // The object that indicates a megamorphic state.
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate); static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
// The object that indicates a premonomorphic state. // The object that indicates a premonomorphic state.
static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate); static inline Handle<Symbol> PremonomorphicSentinel(Isolate* isolate);
// A raw version of the uninitialized sentinel that's safe to read during // A raw version of the uninitialized sentinel that's safe to read during
// garbage collection (e.g., for patching the cache). // garbage collection (e.g., for patching the cache).
static inline Object* RawUninitializedSentinel(Isolate* isolate); static inline Symbol* RawUninitializedSentinel(Isolate* isolate);
static const int kDummyLoadICSlot = 0; static const int kDummyLoadICSlot = 0;
static const int kDummyKeyedLoadICSlot = 2; static const int kDummyKeyedLoadICSlot = 2;
......
...@@ -65,21 +65,21 @@ snippet: " ...@@ -65,21 +65,21 @@ snippet: "
" "
frame size: 8 frame size: 8
parameter count: 1 parameter count: 1
bytecode array length: 44 bytecode array length: 45
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
B(Star), R(1), B(Star), R(1),
B(JumpIfUndefined), U8(37), B(JumpIfUndefined), U8(38),
B(JumpIfNull), U8(35), B(JumpIfNull), U8(36),
B(ToObject), B(ToObject),
B(Star), R(3), B(Star), R(3),
B(ForInPrepare), R(4), B(ForInPrepare), R(4),
B(LdaZero), B(LdaZero),
B(Star), R(7), B(Star), R(7),
B(ForInDone), R(7), R(6), B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(22), B(JumpIfTrue), U8(23),
B(ForInNext), R(3), R(7), R(4), B(ForInNext), R(3), R(7), R(4), U8(1),
B(JumpIfUndefined), U8(10), B(JumpIfUndefined), U8(10),
B(Star), R(0), B(Star), R(0),
B(StackCheck), B(StackCheck),
...@@ -88,7 +88,7 @@ bytecodes: [ ...@@ -88,7 +88,7 @@ bytecodes: [
B(Return), B(Return),
B(ForInStep), R(7), B(ForInStep), R(7),
B(Star), R(7), B(Star), R(7),
B(Jump), U8(-23), B(Jump), U8(-24),
B(LdaUndefined), B(LdaUndefined),
B(Return), B(Return),
] ]
...@@ -105,22 +105,22 @@ snippet: " ...@@ -105,22 +105,22 @@ snippet: "
" "
frame size: 9 frame size: 9
parameter count: 1 parameter count: 1
bytecode array length: 56 bytecode array length: 57
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(LdaZero), B(LdaZero),
B(Star), R(1), B(Star), R(1),
B(CreateArrayLiteral), U8(0), U8(0), U8(3), B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(JumpIfUndefined), U8(46), B(JumpIfUndefined), U8(47),
B(JumpIfNull), U8(44), B(JumpIfNull), U8(45),
B(ToObject), B(ToObject),
B(Star), R(3), B(Star), R(3),
B(ForInPrepare), R(4), B(ForInPrepare), R(4),
B(LdaZero), B(LdaZero),
B(Star), R(7), B(Star), R(7),
B(ForInDone), R(7), R(6), B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(31), B(JumpIfTrue), U8(32),
B(ForInNext), R(3), R(7), R(4), B(ForInNext), R(3), R(7), R(4), U8(1),
B(JumpIfUndefined), U8(19), B(JumpIfUndefined), U8(19),
B(Star), R(0), B(Star), R(0),
B(StackCheck), B(StackCheck),
...@@ -133,7 +133,7 @@ bytecodes: [ ...@@ -133,7 +133,7 @@ bytecodes: [
B(Star), R(1), B(Star), R(1),
B(ForInStep), R(7), B(ForInStep), R(7),
B(Star), R(7), B(Star), R(7),
B(Jump), U8(-32), B(Jump), U8(-33),
B(LdaUndefined), B(LdaUndefined),
B(Return), B(Return),
] ]
...@@ -153,23 +153,23 @@ snippet: " ...@@ -153,23 +153,23 @@ snippet: "
" "
frame size: 8 frame size: 8
parameter count: 1 parameter count: 1
bytecode array length: 93 bytecode array length: 94
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(CreateObjectLiteral), U8(0), U8(0), U8(9), B(CreateObjectLiteral), U8(0), U8(0), U8(9),
B(Star), R(1), B(Star), R(1),
B(Star), R(0), B(Star), R(0),
B(CreateArrayLiteral), U8(1), U8(1), U8(3), B(CreateArrayLiteral), U8(1), U8(1), U8(3),
B(JumpIfUndefined), U8(78), B(JumpIfUndefined), U8(79),
B(JumpIfNull), U8(76), B(JumpIfNull), U8(77),
B(ToObject), B(ToObject),
B(Star), R(1), B(Star), R(1),
B(ForInPrepare), R(2), B(ForInPrepare), R(2),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(ForInDone), R(5), R(4), B(ForInDone), R(5), R(4),
B(JumpIfTrue), U8(63), B(JumpIfTrue), U8(64),
B(ForInNext), R(1), R(5), R(2), B(ForInNext), R(1), R(5), R(2), U8(9),
B(JumpIfUndefined), U8(51), B(JumpIfUndefined), U8(51),
B(Star), R(6), B(Star), R(6),
B(Ldar), R(0), B(Ldar), R(0),
...@@ -195,7 +195,7 @@ bytecodes: [ ...@@ -195,7 +195,7 @@ bytecodes: [
B(Jump), U8(8), B(Jump), U8(8),
B(ForInStep), R(5), B(ForInStep), R(5),
B(Star), R(5), B(Star), R(5),
B(Jump), U8(-64), B(Jump), U8(-65),
B(LdaUndefined), B(LdaUndefined),
B(Return), B(Return),
] ]
...@@ -214,22 +214,22 @@ snippet: " ...@@ -214,22 +214,22 @@ snippet: "
" "
frame size: 9 frame size: 9
parameter count: 1 parameter count: 1
bytecode array length: 68 bytecode array length: 69
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(CreateArrayLiteral), U8(0), U8(0), U8(3), B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(0), B(Star), R(0),
B(CreateArrayLiteral), U8(1), U8(1), U8(3), B(CreateArrayLiteral), U8(1), U8(1), U8(3),
B(JumpIfUndefined), U8(55), B(JumpIfUndefined), U8(56),
B(JumpIfNull), U8(53), B(JumpIfNull), U8(54),
B(ToObject), B(ToObject),
B(Star), R(1), B(Star), R(1),
B(ForInPrepare), R(2), B(ForInPrepare), R(2),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(ForInDone), R(5), R(4), B(ForInDone), R(5), R(4),
B(JumpIfTrue), U8(40), B(JumpIfTrue), U8(41),
B(ForInNext), R(1), R(5), R(2), B(ForInNext), R(1), R(5), R(2), U8(7),
B(JumpIfUndefined), U8(28), B(JumpIfUndefined), U8(28),
B(Star), R(6), B(Star), R(6),
B(Ldar), R(0), B(Ldar), R(0),
...@@ -246,7 +246,7 @@ bytecodes: [ ...@@ -246,7 +246,7 @@ bytecodes: [
B(Return), B(Return),
B(ForInStep), R(5), B(ForInStep), R(5),
B(Star), R(5), B(Star), R(5),
B(Jump), U8(-41), B(Jump), U8(-42),
B(LdaUndefined), B(LdaUndefined),
B(Return), B(Return),
] ]
......
...@@ -1125,7 +1125,7 @@ snippet: " ...@@ -1125,7 +1125,7 @@ snippet: "
" "
frame size: 167 frame size: 167
parameter count: 1 parameter count: 1
bytecode array length: 109 bytecode array length: 111
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
...@@ -1133,8 +1133,8 @@ bytecodes: [ ...@@ -1133,8 +1133,8 @@ bytecodes: [
B(LdaZero), B(LdaZero),
B(Star), R(1), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
B(JumpIfUndefined), U8(96), B(JumpIfUndefined), U8(98),
B(JumpIfNull), U8(94), B(JumpIfNull), U8(96),
B(ToObject), B(ToObject),
B(Star), R(125), B(Star), R(125),
B(MovWide), R16(125), R16(161), B(MovWide), R16(125), R16(161),
...@@ -1145,8 +1145,8 @@ bytecodes: [ ...@@ -1145,8 +1145,8 @@ bytecodes: [
B(MovWide), R16(165), R16(125), B(MovWide), R16(165), R16(125),
B(MovWide), R16(164), R16(126), B(MovWide), R16(164), R16(126),
B(ForInDone), R(125), R(126), B(ForInDone), R(125), R(126),
B(JumpIfTrue), U8(60), B(JumpIfTrue), U8(62),
B(ForInNextWide), R16(161), R16(165), R16(162), B(ForInNextWide), R16(161), R16(165), R16(162), U16(1),
B(JumpIfUndefined), U8(35), B(JumpIfUndefined), U8(35),
B(Star), R(125), B(Star), R(125),
B(MovWide), R16(125), R16(132), B(MovWide), R16(125), R16(132),
...@@ -1163,7 +1163,7 @@ bytecodes: [ ...@@ -1163,7 +1163,7 @@ bytecodes: [
B(ForInStep), R(125), B(ForInStep), R(125),
B(Star), R(125), B(Star), R(125),
B(MovWide), R16(125), R16(165), B(MovWide), R16(125), R16(165),
B(Jump), U8(-71), B(Jump), U8(-73),
B(Ldar), R(1), B(Ldar), R(1),
B(Return), B(Return),
] ]
......
...@@ -205,11 +205,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -205,11 +205,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.ForInPrepare(reg) builder.ForInPrepare(reg)
.ForInDone(reg, reg) .ForInDone(reg, reg)
.ForInNext(reg, reg, reg) .ForInNext(reg, reg, reg, 1)
.ForInStep(reg); .ForInStep(reg);
builder.ForInPrepare(wide) builder.ForInPrepare(wide)
.ForInDone(reg, other) .ForInDone(reg, other)
.ForInNext(wide, wide, wide) .ForInNext(wide, wide, wide, 1024)
.ForInStep(reg); .ForInStep(reg);
// Wide constant pool loads // Wide constant pool loads
......
...@@ -249,9 +249,9 @@ TEST_F(RegisterTranslatorTest, BadRange2) { ...@@ -249,9 +249,9 @@ TEST_F(RegisterTranslatorTest, BadRange2) {
Register cache_info_pair(194); Register cache_info_pair(194);
Register cache_info_pair_translated(cache_info_pair.index() + window_width()); Register cache_info_pair_translated(cache_info_pair.index() + window_width());
uint32_t operands[] = {receiver.ToRawOperand(), index.ToRawOperand(), uint32_t operands[] = {receiver.ToRawOperand(), index.ToRawOperand(),
cache_info_pair.ToRawOperand()}; cache_info_pair.ToRawOperand(), 1};
ASSERT_DEATH_IF_SUPPORTED( ASSERT_DEATH_IF_SUPPORTED(
translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 3), translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 4),
kBadOperandRegex); kBadOperandRegex);
} }
......
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