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,
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) {
if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
Handle<Object> root = isolate()->heap()->root_handle(root_index);
......
......@@ -221,6 +221,10 @@ class CodeStubAssembler {
int additional_offset = 0);
Node* LoadFixedArrayElementConstantIndex(Node* object, int index);
// Store an array element to a FixedArray.
Node* StoreFixedArrayElementNoWriteBarrier(Node* object, Node* index,
Node* value);
protected:
// Protected helpers which delegate to RawMachineAssembler.
Graph* graph();
......
......@@ -996,17 +996,21 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
return *this;
}
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) &&
FitsInReg8Operand(cache_type_array_pair)) {
FitsInReg8Operand(cache_type_array_pair) &&
FitsInIdx8Operand(feedback_slot)) {
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) &&
FitsInReg16Operand(cache_type_array_pair)) {
FitsInReg16Operand(cache_type_array_pair) &&
FitsInIdx16Operand(feedback_slot)) {
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 {
UNIMPLEMENTED();
}
......
......@@ -246,7 +246,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple);
BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
Register cache_type_array_pair);
Register cache_type_array_pair,
int feedback_slot);
BytecodeArrayBuilder& ForInStep(Register index);
// Exception handling.
......
......@@ -1129,7 +1129,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->ForInDone(index, cache_length);
loop_builder.BreakIfTrue();
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();
VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
VisitIterationBody(stmt, &loop_builder);
......
......@@ -265,9 +265,10 @@ namespace interpreter {
V(ForInPrepare, OperandType::kRegOutTriple8) \
V(ForInPrepareWide, OperandType::kRegOutTriple16) \
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, \
OperandType::kRegPair16) \
OperandType::kRegPair16, OperandType::kIdx16) \
V(ForInStep, OperandType::kReg8) \
\
/* Perform a stack guard check */ \
......
......@@ -1830,11 +1830,38 @@ void Interpreter::DoForInNext(InterpreterAssembler* assembler) {
Node* cache_type = __ LoadRegister(cache_type_reg);
Node* cache_array_reg = __ NextRegister(cache_type_reg);
Node* cache_array = __ LoadRegister(cache_array_reg);
Node* context = __ GetContext();
Node* result = __ CallRuntime(Runtime::kForInNext, context, receiver,
cache_array, cache_type, index);
__ SetAccumulator(result);
__ Dispatch();
// Load the next key from the enumeration array.
Node* key = __ LoadFixedArrayElementSmiIndex(cache_array, index);
// 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) {
*generic = gen;
}
Handle<Object> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
Handle<Symbol> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
return isolate->factory()->uninitialized_symbol();
}
Handle<Object> TypeFeedbackVector::MegamorphicSentinel(Isolate* isolate) {
Handle<Symbol> TypeFeedbackVector::MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->megamorphic_symbol();
}
Handle<Object> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
Handle<Symbol> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
return isolate->factory()->premonomorphic_symbol();
}
Object* TypeFeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
Symbol* TypeFeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
return isolate->heap()->uninitialized_symbol();
}
......
......@@ -231,17 +231,17 @@ class TypeFeedbackVector : public FixedArray {
void ClearKeyedStoreICs(SharedFunctionInfo* shared);
// 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.
static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
// 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
// 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 kDummyKeyedLoadICSlot = 2;
......
......@@ -65,21 +65,21 @@ snippet: "
"
frame size: 8
parameter count: 1
bytecode array length: 44
bytecode array length: 45
bytecodes: [
B(StackCheck),
B(LdaConstant), U8(0),
B(Star), R(1),
B(JumpIfUndefined), U8(37),
B(JumpIfNull), U8(35),
B(JumpIfUndefined), U8(38),
B(JumpIfNull), U8(36),
B(ToObject),
B(Star), R(3),
B(ForInPrepare), R(4),
B(LdaZero),
B(Star), R(7),
B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(22),
B(ForInNext), R(3), R(7), R(4),
B(JumpIfTrue), U8(23),
B(ForInNext), R(3), R(7), R(4), U8(1),
B(JumpIfUndefined), U8(10),
B(Star), R(0),
B(StackCheck),
......@@ -88,7 +88,7 @@ bytecodes: [
B(Return),
B(ForInStep), R(7),
B(Star), R(7),
B(Jump), U8(-23),
B(Jump), U8(-24),
B(LdaUndefined),
B(Return),
]
......@@ -105,22 +105,22 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 56
bytecode array length: 57
bytecodes: [
B(StackCheck),
B(LdaZero),
B(Star), R(1),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(JumpIfUndefined), U8(46),
B(JumpIfNull), U8(44),
B(JumpIfUndefined), U8(47),
B(JumpIfNull), U8(45),
B(ToObject),
B(Star), R(3),
B(ForInPrepare), R(4),
B(LdaZero),
B(Star), R(7),
B(ForInDone), R(7), R(6),
B(JumpIfTrue), U8(31),
B(ForInNext), R(3), R(7), R(4),
B(JumpIfTrue), U8(32),
B(ForInNext), R(3), R(7), R(4), U8(1),
B(JumpIfUndefined), U8(19),
B(Star), R(0),
B(StackCheck),
......@@ -133,7 +133,7 @@ bytecodes: [
B(Star), R(1),
B(ForInStep), R(7),
B(Star), R(7),
B(Jump), U8(-32),
B(Jump), U8(-33),
B(LdaUndefined),
B(Return),
]
......@@ -153,23 +153,23 @@ snippet: "
"
frame size: 8
parameter count: 1
bytecode array length: 93
bytecode array length: 94
bytecodes: [
B(StackCheck),
B(CreateObjectLiteral), U8(0), U8(0), U8(9),
B(Star), R(1),
B(Star), R(0),
B(CreateArrayLiteral), U8(1), U8(1), U8(3),
B(JumpIfUndefined), U8(78),
B(JumpIfNull), U8(76),
B(JumpIfUndefined), U8(79),
B(JumpIfNull), U8(77),
B(ToObject),
B(Star), R(1),
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(5), R(2),
B(JumpIfTrue), U8(64),
B(ForInNext), R(1), R(5), R(2), U8(9),
B(JumpIfUndefined), U8(51),
B(Star), R(6),
B(Ldar), R(0),
......@@ -195,7 +195,7 @@ bytecodes: [
B(Jump), U8(8),
B(ForInStep), R(5),
B(Star), R(5),
B(Jump), U8(-64),
B(Jump), U8(-65),
B(LdaUndefined),
B(Return),
]
......@@ -214,22 +214,22 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 68
bytecode array length: 69
bytecodes: [
B(StackCheck),
B(CreateArrayLiteral), U8(0), U8(0), U8(3),
B(Star), R(0),
B(CreateArrayLiteral), U8(1), U8(1), U8(3),
B(JumpIfUndefined), U8(55),
B(JumpIfNull), U8(53),
B(JumpIfUndefined), U8(56),
B(JumpIfNull), U8(54),
B(ToObject),
B(Star), R(1),
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(5), R(2),
B(JumpIfTrue), U8(41),
B(ForInNext), R(1), R(5), R(2), U8(7),
B(JumpIfUndefined), U8(28),
B(Star), R(6),
B(Ldar), R(0),
......@@ -246,7 +246,7 @@ bytecodes: [
B(Return),
B(ForInStep), R(5),
B(Star), R(5),
B(Jump), U8(-41),
B(Jump), U8(-42),
B(LdaUndefined),
B(Return),
]
......
......@@ -1125,7 +1125,7 @@ snippet: "
"
frame size: 167
parameter count: 1
bytecode array length: 109
bytecode array length: 111
bytecodes: [
B(StackCheck),
B(LdaConstant), U8(0),
......@@ -1133,8 +1133,8 @@ bytecodes: [
B(LdaZero),
B(Star), R(1),
B(Ldar), R(0),
B(JumpIfUndefined), U8(96),
B(JumpIfNull), U8(94),
B(JumpIfUndefined), U8(98),
B(JumpIfNull), U8(96),
B(ToObject),
B(Star), R(125),
B(MovWide), R16(125), R16(161),
......@@ -1145,8 +1145,8 @@ bytecodes: [
B(MovWide), R16(165), R16(125),
B(MovWide), R16(164), R16(126),
B(ForInDone), R(125), R(126),
B(JumpIfTrue), U8(60),
B(ForInNextWide), R16(161), R16(165), R16(162),
B(JumpIfTrue), U8(62),
B(ForInNextWide), R16(161), R16(165), R16(162), U16(1),
B(JumpIfUndefined), U8(35),
B(Star), R(125),
B(MovWide), R16(125), R16(132),
......@@ -1163,7 +1163,7 @@ bytecodes: [
B(ForInStep), R(125),
B(Star), R(125),
B(MovWide), R16(125), R16(165),
B(Jump), U8(-71),
B(Jump), U8(-73),
B(Ldar), R(1),
B(Return),
]
......
......@@ -205,11 +205,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.ForInPrepare(reg)
.ForInDone(reg, reg)
.ForInNext(reg, reg, reg)
.ForInNext(reg, reg, reg, 1)
.ForInStep(reg);
builder.ForInPrepare(wide)
.ForInDone(reg, other)
.ForInNext(wide, wide, wide)
.ForInNext(wide, wide, wide, 1024)
.ForInStep(reg);
// Wide constant pool loads
......
......@@ -249,9 +249,9 @@ TEST_F(RegisterTranslatorTest, BadRange2) {
Register cache_info_pair(194);
Register cache_info_pair_translated(cache_info_pair.index() + window_width());
uint32_t operands[] = {receiver.ToRawOperand(), index.ToRawOperand(),
cache_info_pair.ToRawOperand()};
cache_info_pair.ToRawOperand(), 1};
ASSERT_DEATH_IF_SUPPORTED(
translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 3),
translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 4),
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