[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:
parent
57ce7d674c
commit
1915762cc8
@ -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(); }
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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) \
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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_; }
|
||||
|
||||
|
@ -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:
|
||||
|
@ -150,10 +150,8 @@
|
||||
V(JSCallFunction) \
|
||||
V(JSCallRuntime) \
|
||||
V(JSConvertReceiver) \
|
||||
V(JSForInDone) \
|
||||
V(JSForInNext) \
|
||||
V(JSForInPrepare) \
|
||||
V(JSForInStep) \
|
||||
V(JSLoadMessage) \
|
||||
V(JSStoreMessage) \
|
||||
V(JSGeneratorStore) \
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user