Index: src/ia32/full-codegen-ia32.cc |
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc |
index 857622d5459d2f9351f716c63770c35da2f23e1a..bacea586df588b95fa88224e7ba63d36bca39438 100644 |
--- a/src/ia32/full-codegen-ia32.cc |
+++ b/src/ia32/full-codegen-ia32.cc |
@@ -925,6 +925,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ cmp(eax, isolate()->factory()->null_value()); |
__ j(equal, &exit); |
+ PrepareForBailoutForId(stmt->PrepareId(), TOS_REG); |
+ |
// Convert the object to a JS object. |
Label convert, done_convert; |
__ JumpIfSmi(eax, &convert, Label::kNear); |
@@ -937,7 +939,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ push(eax); |
// Check for proxies. |
- Label call_runtime; |
+ Label call_runtime, use_cache, fixed_array; |
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
__ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx); |
__ j(below_equal, &call_runtime); |
@@ -946,61 +948,19 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
// the JSObject::IsSimpleEnum cache validity checks. If we cannot |
// guarantee cache validity, call the runtime system to check cache |
// validity or get the property names in a fixed array. |
- Label next; |
- __ mov(ecx, eax); |
- __ bind(&next); |
- |
- // Check that there are no elements. Register ecx contains the |
- // current JS object we've reached through the prototype chain. |
- __ cmp(FieldOperand(ecx, JSObject::kElementsOffset), |
- isolate()->factory()->empty_fixed_array()); |
- __ j(not_equal, &call_runtime); |
- |
- // Check that instance descriptors are not empty so that we can |
- // check for an enum cache. Leave the map in ebx for the subsequent |
- // prototype load. |
- __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
- __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset)); |
- __ JumpIfSmi(edx, &call_runtime); |
- |
- // Check that there is an enum cache in the non-empty instance |
- // descriptors (edx). This is the case if the next enumeration |
- // index field does not contain a smi. |
- __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
- __ JumpIfSmi(edx, &call_runtime); |
- |
- // For all objects but the receiver, check that the cache is empty. |
- Label check_prototype; |
- __ cmp(ecx, eax); |
- __ j(equal, &check_prototype, Label::kNear); |
- __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
- __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
- __ j(not_equal, &call_runtime); |
- |
- // Load the prototype from the map and loop if non-null. |
- __ bind(&check_prototype); |
- __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
- __ cmp(ecx, isolate()->factory()->null_value()); |
- __ j(not_equal, &next); |
+ __ CheckEnumCache(&call_runtime); |
- // The enum cache is valid. Load the map of the object being |
- // iterated over and use the cache for the iteration. |
- Label use_cache; |
__ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
__ jmp(&use_cache, Label::kNear); |
// Get the set of properties to enumerate. |
__ bind(&call_runtime); |
- __ push(eax); // Duplicate the enumerable object on the stack. |
+ __ push(eax); |
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
- |
- // If we got a map from the runtime call, we can do a fast |
- // modification check. Otherwise, we got a fixed array, and we have |
- // to do a slow check. |
- Label fixed_array; |
__ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
isolate()->factory()->meta_map()); |
- __ j(not_equal, &fixed_array, Label::kNear); |
+ __ j(not_equal, &fixed_array); |
+ |
// We got a map in register eax. Get the enumeration cache from it. |
__ bind(&use_cache); |
@@ -1033,6 +993,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ push(Immediate(Smi::FromInt(0))); // Initial index. |
// Generate code for doing the condition check. |
+ PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); |
__ bind(&loop); |
__ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. |
__ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. |
@@ -1075,7 +1036,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ mov(result_register(), ebx); |
// Perform the assignment as if via '='. |
{ EffectContext context(this); |
- EmitAssignment(stmt->each(), stmt->AssignmentId()); |
+ EmitAssignment(stmt->each()); |
} |
// Generate code for the body of the loop. |
@@ -1094,6 +1055,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ add(esp, Immediate(5 * kPointerSize)); |
// Exit and decrement the loop depth. |
+ PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
__ bind(&exit); |
decrement_loop_depth(); |
} |
@@ -1853,7 +1815,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
} |
-void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
+void FullCodeGenerator::EmitAssignment(Expression* expr) { |
// Invalid left-hand sides are rewritten to have a 'throw |
// ReferenceError' on the left-hand side. |
if (!expr->IsValidLeftHandSide()) { |
@@ -1905,7 +1867,6 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
break; |
} |
} |
- PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
context()->Plug(eax); |
} |