| 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);
|
| }
|
|
|
|
|