From 825ece488b8343b4a8e3637130dfab9030844f34 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Sun, 24 Jan 2016 22:00:26 -0800 Subject: [PATCH] [turbofan] Switch JSForInPrepare to %ForInPrepare style. Now TurboFan always uses the newly introduced %ForInPrepare, no matter whether baseline is the interpreter or fullcodegen. For fullcodegen, we introduce a new PrepareId bailout point for this purpose. Drive-by-fix: Avoid the NoObservableSideEffectsScope in Crankshaft and use the PrepareId bailout point instead. R=jarin@chromium.org BUG=v8:3650 LOG=n Review URL: https://codereview.chromium.org/1630523002 Cr-Commit-Position: refs/heads/master@{#33480} --- src/ast/ast.h | 7 +- src/compiler/ast-graph-builder.cc | 3 +- src/compiler/js-generic-lowering.cc | 168 +----------------- src/compiler/js-typed-lowering.cc | 155 ---------------- src/compiler/js-typed-lowering.h | 1 - src/compiler/typer.cc | 5 + src/crankshaft/hydrogen.cc | 73 ++++---- src/full-codegen/arm/full-codegen-arm.cc | 4 +- src/full-codegen/arm64/full-codegen-arm64.cc | 5 +- src/full-codegen/ia32/full-codegen-ia32.cc | 1 + src/full-codegen/mips/full-codegen-mips.cc | 4 +- .../mips64/full-codegen-mips64.cc | 4 +- src/full-codegen/ppc/full-codegen-ppc.cc | 4 +- src/full-codegen/x64/full-codegen-x64.cc | 1 + src/full-codegen/x87/full-codegen-x87.cc | 1 + 15 files changed, 63 insertions(+), 373 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 21f5aef151..7c53d7f42c 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -862,12 +862,13 @@ 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() + 5; } + static int num_ids() { return parent_num_ids() + 6; } 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 FilterId() const { return BailoutId(local_id(3)); } - BailoutId AssignmentId() const { return BailoutId(local_id(4)); } + 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 ContinueId() const override { return EntryId(); } BailoutId StackCheckId() const override { return BodyId(); } diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index ceea7890b4..765664cf30 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -1331,7 +1331,8 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { // Prepare for-in cache. Node* prepare = NewNode(javascript()->ForInPrepare(), object); - PrepareFrameState(prepare, stmt->EnumId(), OutputFrameStateCombine::Push()); + PrepareFrameState(prepare, stmt->PrepareId(), + OutputFrameStateCombine::Push(3)); Node* cache_type = NewNode(common()->Projection(0), prepare); Node* cache_array = NewNode(common()->Projection(1), prepare); Node* cache_length = NewNode(common()->Projection(2), prepare); diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index f40e71c6d0..ebbd4ed163 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -616,173 +616,7 @@ void JSGenericLowering::LowerJSForInNext(Node* node) { void JSGenericLowering::LowerJSForInPrepare(Node* node) { - Node* object = NodeProperties::GetValueInput(node, 0); - Node* context = NodeProperties::GetContextInput(node); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); - - // Get the set of properties to enumerate. - Runtime::Function const* function = - Runtime::FunctionForId(Runtime::kGetPropertyNamesFast); - CallDescriptor const* descriptor = Linkage::GetRuntimeCallDescriptor( - zone(), function->function_id, 1, Operator::kNoProperties, - CallDescriptor::kNeedsFrameState); - Node* cache_type = effect = graph()->NewNode( - common()->Call(descriptor), - jsgraph()->CEntryStubConstant(function->result_size), object, - jsgraph()->ExternalConstant(function->function_id), - jsgraph()->Int32Constant(1), context, frame_state, effect, control); - control = graph()->NewNode(common()->IfSuccess(), cache_type); - - Node* object_map = effect = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), object, - jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), - effect, control); - Node* cache_type_map = effect = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), cache_type, - jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), - effect, control); - Node* meta_map = jsgraph()->HeapConstant(isolate()->factory()->meta_map()); - - // If we got a map from the GetPropertyNamesFast runtime call, we can do a - // fast modification check. Otherwise, we got a fixed array, and we have to - // perform a slow check on every iteration. - Node* check0 = - graph()->NewNode(machine()->WordEqual(), cache_type_map, meta_map); - Node* branch0 = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); - - Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); - Node* cache_array_true0; - Node* cache_length_true0; - Node* cache_type_true0; - Node* etrue0; - { - // Enum cache case. - Node* cache_type_enum_length = etrue0 = graph()->NewNode( - machine()->Load(MachineType::Uint32()), cache_type, - jsgraph()->IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag), - effect, if_true0); - cache_type_enum_length = - graph()->NewNode(machine()->Word32And(), cache_type_enum_length, - jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask)); - - Node* check1 = - graph()->NewNode(machine()->Word32Equal(), cache_type_enum_length, - jsgraph()->Int32Constant(0)); - Node* branch1 = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); - - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* cache_array_true1; - Node* etrue1; - { - // No properties to enumerate. - cache_array_true1 = - jsgraph()->HeapConstant(isolate()->factory()->empty_fixed_array()); - etrue1 = etrue0; - } - - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* cache_array_false1; - Node* efalse1; - { - // Load the enumeration cache from the instance descriptors of {object}. - Node* object_map_descriptors = efalse1 = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), object_map, - jsgraph()->IntPtrConstant(Map::kDescriptorsOffset - kHeapObjectTag), - etrue0, if_false1); - Node* object_map_enum_cache = efalse1 = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), object_map_descriptors, - jsgraph()->IntPtrConstant(DescriptorArray::kEnumCacheOffset - - kHeapObjectTag), - efalse1, if_false1); - cache_array_false1 = efalse1 = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), object_map_enum_cache, - jsgraph()->IntPtrConstant( - DescriptorArray::kEnumCacheBridgeCacheOffset - kHeapObjectTag), - efalse1, if_false1); - } - - if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); - etrue0 = - graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); - cache_array_true0 = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_array_true1, cache_array_false1, if_true0); - - cache_length_true0 = graph()->NewNode( - machine()->WordShl(), - machine()->Is64() - ? graph()->NewNode(machine()->ChangeUint32ToUint64(), - cache_type_enum_length) - : cache_type_enum_length, - jsgraph()->Int32Constant(kSmiShiftSize + kSmiTagSize)); - cache_type_true0 = cache_type; - } - - Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); - Node* cache_array_false0; - Node* cache_length_false0; - Node* cache_type_false0; - Node* efalse0; - { - // FixedArray case. - cache_type_false0 = jsgraph()->OneConstant(); // Smi means slow check - cache_array_false0 = cache_type; - cache_length_false0 = efalse0 = graph()->NewNode( - machine()->Load(MachineType::AnyTagged()), cache_array_false0, - jsgraph()->IntPtrConstant(FixedArray::kLengthOffset - kHeapObjectTag), - effect, if_false0); - } - - control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); - effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); - Node* cache_array = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_array_true0, cache_array_false0, control); - Node* cache_length = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_length_true0, cache_length_false0, control); - cache_type = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_type_true0, cache_type_false0, control); - - for (auto edge : node->use_edges()) { - if (NodeProperties::IsEffectEdge(edge)) { - edge.UpdateTo(effect); - } else if (NodeProperties::IsControlEdge(edge)) { - Node* const use = edge.from(); - if (use->opcode() == IrOpcode::kIfSuccess) { - use->ReplaceUses(control); - use->Kill(); - } else if (use->opcode() == IrOpcode::kIfException) { - edge.UpdateTo(cache_type_true0); - } else { - UNREACHABLE(); - } - } else { - Node* const use = edge.from(); - DCHECK(NodeProperties::IsValueEdge(edge)); - DCHECK_EQ(IrOpcode::kProjection, use->opcode()); - switch (ProjectionIndexOf(use->op())) { - case 0: - use->ReplaceUses(cache_type); - break; - case 1: - use->ReplaceUses(cache_array); - break; - case 2: - use->ReplaceUses(cache_length); - break; - default: - UNREACHABLE(); - break; - } - use->Kill(); - } - } + ReplaceWithRuntimeCall(node, Runtime::kForInPrepare); } diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 8fb28a600c..d13355a610 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -2270,159 +2270,6 @@ Reduction JSTypedLowering::ReduceJSForInDone(Node* node) { } -Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) { - DCHECK_EQ(IrOpcode::kJSForInPrepare, node->opcode()); - Node* receiver = NodeProperties::GetValueInput(node, 0); - Node* context = NodeProperties::GetContextInput(node); - Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - - // Get the set of properties to enumerate. - Node* cache_type = effect = graph()->NewNode( - javascript()->CallRuntime(Runtime::kGetPropertyNamesFast), receiver, - context, frame_state, effect, control); - control = graph()->NewNode(common()->IfSuccess(), cache_type); - - Node* receiver_map = effect = - graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), - receiver, effect, control); - Node* cache_type_map = effect = - graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), - cache_type, effect, control); - Node* meta_map = jsgraph()->HeapConstant(factory()->meta_map()); - - // If we got a map from the GetPropertyNamesFast runtime call, we can do a - // fast modification check. Otherwise, we got a fixed array, and we have to - // perform a slow check on every iteration. - Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), - cache_type_map, meta_map); - Node* branch0 = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); - - Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); - Node* cache_array_true0; - Node* cache_length_true0; - Node* cache_type_true0; - Node* etrue0; - { - // Enum cache case. - Node* cache_type_enum_length = etrue0 = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForMapBitField3()), cache_type, - effect, if_true0); - cache_length_true0 = graph()->NewNode( - simplified()->NumberBitwiseAnd(), cache_type_enum_length, - jsgraph()->Int32Constant(Map::EnumLengthBits::kMask)); - - Node* check1 = - graph()->NewNode(machine()->Word32Equal(), cache_length_true0, - jsgraph()->Int32Constant(0)); - Node* branch1 = - graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); - - Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); - Node* cache_array_true1; - Node* etrue1; - { - // No properties to enumerate. - cache_array_true1 = - jsgraph()->HeapConstant(factory()->empty_fixed_array()); - etrue1 = etrue0; - } - - Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); - Node* cache_array_false1; - Node* efalse1; - { - // Load the enumeration cache from the instance descriptors of {receiver}. - Node* receiver_map_descriptors = efalse1 = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForMapDescriptors()), - receiver_map, etrue0, if_false1); - Node* object_map_enum_cache = efalse1 = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()), - receiver_map_descriptors, efalse1, if_false1); - cache_array_false1 = efalse1 = graph()->NewNode( - simplified()->LoadField( - AccessBuilder::ForDescriptorArrayEnumCacheBridgeCache()), - object_map_enum_cache, efalse1, if_false1); - } - - if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); - etrue0 = - graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); - cache_array_true0 = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_array_true1, cache_array_false1, if_true0); - - cache_type_true0 = cache_type; - } - - Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); - Node* cache_array_false0; - Node* cache_length_false0; - Node* cache_type_false0; - Node* efalse0; - { - // FixedArray case. - cache_type_false0 = jsgraph()->OneConstant(); // Smi means slow check - cache_array_false0 = cache_type; - cache_length_false0 = efalse0 = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), - cache_array_false0, effect, if_false0); - } - - control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); - effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); - Node* cache_array = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_array_true0, cache_array_false0, control); - Node* cache_length = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_length_true0, cache_length_false0, control); - cache_type = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), - cache_type_true0, cache_type_false0, control); - - for (auto edge : node->use_edges()) { - Node* const use = edge.from(); - if (NodeProperties::IsEffectEdge(edge)) { - edge.UpdateTo(effect); - Revisit(use); - } else { - if (NodeProperties::IsControlEdge(edge)) { - if (use->opcode() == IrOpcode::kIfSuccess) { - Replace(use, control); - } else if (use->opcode() == IrOpcode::kIfException) { - edge.UpdateTo(cache_type_true0); - continue; - } else { - UNREACHABLE(); - } - } else { - DCHECK(NodeProperties::IsValueEdge(edge)); - DCHECK_EQ(IrOpcode::kProjection, use->opcode()); - switch (ProjectionIndexOf(use->op())) { - case 0: - Replace(use, cache_type); - break; - case 1: - Replace(use, cache_array); - break; - case 2: - Replace(use, cache_length); - break; - default: - UNREACHABLE(); - break; - } - } - use->Kill(); - } - } - return NoChange(); // All uses were replaced already above. -} - - Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode()); Node* receiver = NodeProperties::GetValueInput(node, 0); @@ -2670,8 +2517,6 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceJSForInDone(node); case IrOpcode::kJSForInNext: return ReduceJSForInNext(node); - case IrOpcode::kJSForInPrepare: - return ReduceJSForInPrepare(node); case IrOpcode::kJSForInStep: return ReduceJSForInStep(node); case IrOpcode::kSelect: diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 68ce74e624..fe57716f88 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -83,7 +83,6 @@ class JSTypedLowering final : public AdvancedReducer { Reduction ReduceJSCallFunction(Node* node); Reduction ReduceJSForInDone(Node* node); Reduction ReduceJSForInNext(Node* node); - Reduction ReduceJSForInPrepare(Node* node); Reduction ReduceJSForInStep(Node* node); Reduction ReduceSelect(Node* node); Reduction ReduceNumberBinop(Node* node, const Operator* numberOp); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 7e36f0a315..1024f0a25d 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -650,6 +650,11 @@ Type* Typer::Visitor::TypeCall(Node* node) { return Type::Any(); } Type* Typer::Visitor::TypeProjection(Node* node) { + // TODO(bmeurer): Make this beautiful! Use tuple type here. + if (node->InputAt(0)->opcode() == IrOpcode::kJSForInPrepare && + ProjectionIndexOf(node->op()) == 2) { + return typer_->cache_.kSmi; + } // TODO(titzer): use the output type of the input to determine the bounds. return Type::Any(); } diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc index 090223606c..d2ba73c1da 100644 --- a/src/crankshaft/hydrogen.cc +++ b/src/crankshaft/hydrogen.cc @@ -5315,69 +5315,62 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt, Variable* each_var, HValue* enumerable) { - HValue* map; - HValue* array; - HValue* enum_length; Handle meta_map = isolate()->factory()->meta_map(); bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN; BuildCheckHeapObject(enumerable); Add(enumerable, HCheckInstanceType::IS_JS_RECEIVER); Add(stmt->ToObjectId()); if (fast) { - map = Add(enumerable); + HForInPrepareMap* map = Add(enumerable); Push(map); Add(stmt->EnumId()); Drop(1); Add(map, meta_map); - array = Add(enumerable, map, - DescriptorArray::kEnumCacheBridgeCacheIndex); - enum_length = BuildEnumLength(map); + HForInCacheArray* array = Add( + enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); + HValue* enum_length = BuildEnumLength(map); - HInstruction* index_cache = Add( + HForInCacheArray* index_cache = Add( enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); - HForInCacheArray::cast(array) - ->set_index_cache(HForInCacheArray::cast(index_cache)); + array->set_index_cache(index_cache); + + Push(map); + Push(array); + Push(enum_length); + Add(stmt->PrepareId()); } else { Runtime::FunctionId function_id = Runtime::kGetPropertyNamesFast; Add(enumerable); - array = Add(Runtime::FunctionForId(function_id), 1); + HCallRuntime* array = + Add(Runtime::FunctionForId(function_id), 1); Push(array); Add(stmt->EnumId()); Drop(1); + + IfBuilder if_fast(this); + if_fast.If(array, meta_map); + if_fast.Then(); { - NoObservableSideEffectsScope scope(this); - IfBuilder if_fast(this); - if_fast.If(array, meta_map); - if_fast.Then(); - { - HValue* cache_map = array; - HForInCacheArray* cache = Add( - enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex); - enum_length = BuildEnumLength(cache_map); - Push(cache_map); - Push(cache); - Push(enum_length); - } - if_fast.Else(); - { - Push(graph()->GetConstant1()); - Push(array); - Push(AddLoadFixedArrayLength(array)); - } - if_fast.End(); - enum_length = Pop(); - array = Pop(); - map = Pop(); + HValue* cache_map = array; + HForInCacheArray* cache = Add( + enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex); + HValue* enum_length = BuildEnumLength(cache_map); + Push(cache_map); + Push(cache); + Push(enum_length); + Add(stmt->PrepareId(), FIXED_SIMULATE); + } + if_fast.Else(); + { + Push(graph()->GetConstant1()); + Push(array); + Push(AddLoadFixedArrayLength(array)); + Add(stmt->PrepareId(), FIXED_SIMULATE); } } - HInstruction* start_index = Add(0); - - Push(map); - Push(array); - Push(enum_length); - Push(start_index); + Push(graph()->GetConstant0()); HBasicBlock* loop_entry = BuildLoopEntry(stmt); diff --git a/src/full-codegen/arm/full-codegen-arm.cc b/src/full-codegen/arm/full-codegen-arm.cc index cac5e6e7c3..6668d19cf4 100644 --- a/src/full-codegen/arm/full-codegen-arm.cc +++ b/src/full-codegen/arm/full-codegen-arm.cc @@ -1125,8 +1125,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ mov(r1, Operand(Smi::FromInt(1))); // Smi(1) indicates slow check __ Push(r1, r0); // Smi and array __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); + __ Push(r1); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ mov(r0, Operand(Smi::FromInt(0))); - __ Push(r1, r0); // Fixed array length (as smi) and initial index. + __ Push(r0); // Initial index. // Generate code for doing the condition check. __ bind(&loop); diff --git a/src/full-codegen/arm64/full-codegen-arm64.cc b/src/full-codegen/arm64/full-codegen-arm64.cc index 3ebd627b93..82f3c218e6 100644 --- a/src/full-codegen/arm64/full-codegen-arm64.cc +++ b/src/full-codegen/arm64/full-codegen-arm64.cc @@ -1120,8 +1120,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(vector_index))); __ Mov(x1, Smi::FromInt(1)); // Smi(1) indicates slow check. __ Ldr(x2, FieldMemOperand(x0, FixedArray::kLengthOffset)); - // Smi and array, fixed array length (as smi) and initial index. - __ Push(x1, x0, x2, xzr); + __ Push(x1, x0, x2); // Smi and array, fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); + __ Push(xzr); // Initial index. // Generate code for doing the condition check. __ Bind(&loop); diff --git a/src/full-codegen/ia32/full-codegen-ia32.cc b/src/full-codegen/ia32/full-codegen-ia32.cc index 997a3539a2..757c672eb8 100644 --- a/src/full-codegen/ia32/full-codegen-ia32.cc +++ b/src/full-codegen/ia32/full-codegen-ia32.cc @@ -1055,6 +1055,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(eax); // Array __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); __ push(eax); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ push(Immediate(Smi::FromInt(0))); // Initial index. // Generate code for doing the condition check. diff --git a/src/full-codegen/mips/full-codegen-mips.cc b/src/full-codegen/mips/full-codegen-mips.cc index c378f96838..4c22f1d82f 100644 --- a/src/full-codegen/mips/full-codegen-mips.cc +++ b/src/full-codegen/mips/full-codegen-mips.cc @@ -1122,8 +1122,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ li(a1, Operand(Smi::FromInt(1))); // Smi(1) indicates slow check __ Push(a1, v0); // Smi and array __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); + __ Push(a1); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ li(a0, Operand(Smi::FromInt(0))); - __ Push(a1, a0); // Fixed array length (as smi) and initial index. + __ Push(a0); // Initial index. // Generate code for doing the condition check. __ bind(&loop); diff --git a/src/full-codegen/mips64/full-codegen-mips64.cc b/src/full-codegen/mips64/full-codegen-mips64.cc index cdaab1fdb1..688a9a1c40 100644 --- a/src/full-codegen/mips64/full-codegen-mips64.cc +++ b/src/full-codegen/mips64/full-codegen-mips64.cc @@ -1122,8 +1122,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ li(a1, Operand(Smi::FromInt(1))); // Smi(1) indicates slow check __ Push(a1, v0); // Smi and array __ ld(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); + __ Push(a1); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ li(a0, Operand(Smi::FromInt(0))); - __ Push(a1, a0); // Fixed array length (as smi) and initial index. + __ Push(a0); // Initial index. // Generate code for doing the condition check. __ bind(&loop); diff --git a/src/full-codegen/ppc/full-codegen-ppc.cc b/src/full-codegen/ppc/full-codegen-ppc.cc index 82d44865a0..82304538d4 100644 --- a/src/full-codegen/ppc/full-codegen-ppc.cc +++ b/src/full-codegen/ppc/full-codegen-ppc.cc @@ -1084,8 +1084,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ LoadSmiLiteral(r4, Smi::FromInt(1)); // Smi(1) indicates slow check __ Push(r4, r3); // Smi and array __ LoadP(r4, FieldMemOperand(r3, FixedArray::kLengthOffset)); + __ Push(r4); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ LoadSmiLiteral(r3, Smi::FromInt(0)); - __ Push(r4, r3); // Fixed array length (as smi) and initial index. + __ Push(r3); // Initial index. // Generate code for doing the condition check. __ bind(&loop); diff --git a/src/full-codegen/x64/full-codegen-x64.cc b/src/full-codegen/x64/full-codegen-x64.cc index 68bb6498a1..d494ac92c7 100644 --- a/src/full-codegen/x64/full-codegen-x64.cc +++ b/src/full-codegen/x64/full-codegen-x64.cc @@ -1077,6 +1077,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ Push(rax); // Array __ movp(rax, FieldOperand(rax, FixedArray::kLengthOffset)); __ Push(rax); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ Push(Smi::FromInt(0)); // Initial index. // Generate code for doing the condition check. diff --git a/src/full-codegen/x87/full-codegen-x87.cc b/src/full-codegen/x87/full-codegen-x87.cc index c5bcaa70f0..860e15b4ee 100644 --- a/src/full-codegen/x87/full-codegen-x87.cc +++ b/src/full-codegen/x87/full-codegen-x87.cc @@ -1047,6 +1047,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ push(eax); // Array __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); __ push(eax); // Fixed array length (as smi). + PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); __ push(Immediate(Smi::FromInt(0))); // Initial index. // Generate code for doing the condition check.