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