| 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..d7a4cc3c34e6c75a33613704c30bc52b6e20303e 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,70 +939,24 @@ 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); | 
|  | 
| -  // Check cache validity in generated code. This is a fast case for | 
| -  // 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 +989,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 +1032,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 +1051,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 +1811,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 +1863,6 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 
| break; | 
| } | 
| } | 
| -  PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 
| context()->Plug(eax); | 
| } | 
|  | 
|  |