| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 6920)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -880,6 +880,10 @@
|
| ForIn loop_statement(this, stmt);
|
| increment_loop_depth();
|
|
|
| + // Load null value as it is used several times below.
|
| + Register null_value = r5;
|
| + __ LoadRoot(null_value, Heap::kNullValueRootIndex);
|
| +
|
| // Get the object to enumerate over. Both SpiderMonkey and JSC
|
| // ignore null and undefined in contrast to the specification; see
|
| // ECMA-262 section 12.6.4.
|
| @@ -887,8 +891,7 @@
|
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| __ cmp(r0, ip);
|
| __ b(eq, &exit);
|
| - __ LoadRoot(ip, Heap::kNullValueRootIndex);
|
| - __ cmp(r0, ip);
|
| + __ cmp(r0, null_value);
|
| __ b(eq, &exit);
|
|
|
| // Convert the object to a JS object.
|
| @@ -902,12 +905,62 @@
|
| __ bind(&done_convert);
|
| __ push(r0);
|
|
|
| - // BUG(867): 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.
|
| + // 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, call_runtime;
|
| + // Preload a couple of values used in the loop.
|
| + Register empty_fixed_array_value = r6;
|
| + __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
|
| + Register empty_descriptor_array_value = r7;
|
| + __ LoadRoot(empty_descriptor_array_value,
|
| + Heap::kEmptyDescriptorArrayRootIndex);
|
| + __ mov(r1, r0);
|
| + __ bind(&next);
|
|
|
| + // Check that there are no elements. Register r1 contains the
|
| + // current JS object we've reached through the prototype chain.
|
| + __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
|
| + __ cmp(r2, empty_fixed_array_value);
|
| + __ b(ne, &call_runtime);
|
| +
|
| + // Check that instance descriptors are not empty so that we can
|
| + // check for an enum cache. Leave the map in r2 for the subsequent
|
| + // prototype load.
|
| + __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
|
| + __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset));
|
| + __ cmp(r3, empty_descriptor_array_value);
|
| + __ b(eq, &call_runtime);
|
| +
|
| + // Check that there is an enum cache in the non-empty instance
|
| + // descriptors (r3). This is the case if the next enumeration
|
| + // index field does not contain a smi.
|
| + __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
|
| + __ JumpIfSmi(r3, &call_runtime);
|
| +
|
| + // For all objects but the receiver, check that the cache is empty.
|
| + Label check_prototype;
|
| + __ cmp(r1, r0);
|
| + __ b(eq, &check_prototype);
|
| + __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
| + __ cmp(r3, empty_fixed_array_value);
|
| + __ b(ne, &call_runtime);
|
| +
|
| + // Load the prototype from the map and loop if non-null.
|
| + __ bind(&check_prototype);
|
| + __ ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
|
| + __ cmp(r1, null_value);
|
| + __ b(ne, &next);
|
| +
|
| + // The enum cache is valid. Load the map of the object being
|
| + // iterated over and use the cache for the iteration.
|
| + Label use_cache;
|
| + __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| + __ b(&use_cache);
|
| +
|
| // Get the set of properties to enumerate.
|
| + __ bind(&call_runtime);
|
| __ push(r0); // Duplicate the enumerable object on the stack.
|
| __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
|
|
| @@ -922,6 +975,7 @@
|
| __ b(ne, &fixed_array);
|
|
|
| // We got a map in register r0. Get the enumeration cache from it.
|
| + __ bind(&use_cache);
|
| __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
|
| __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
|
| __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
|
|