Index: src/ia32/full-codegen-ia32.cc |
=================================================================== |
--- src/ia32/full-codegen-ia32.cc (revision 5444) |
+++ src/ia32/full-codegen-ia32.cc (working copy) |
@@ -756,13 +756,57 @@ |
__ bind(&done_convert); |
__ push(eax); |
- // TODO(kasperl): 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; |
+ __ 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), |
+ 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::kInstanceDescriptorsOffset)); |
+ __ cmp(edx, Factory::empty_descriptor_array()); |
+ __ j(equal, &call_runtime); |
+ |
+ // Check that there in 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)); |
+ __ test(edx, Immediate(kSmiTagMask)); |
+ __ j(zero, &call_runtime); |
+ |
+ // For all objects but the receiver, check that the cache is empty. |
+ Label check_prototype; |
+ __ cmp(ecx, Operand(eax)); |
+ __ j(equal, &check_prototype); |
+ __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
+ __ cmp(edx, 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, Factory::null_value()); |
+ __ j(not_equal, &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; |
+ __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
+ __ jmp(&use_cache); |
+ |
// Get the set of properties to enumerate. |
+ __ bind(&call_runtime); |
__ push(eax); // Duplicate the enumerable object on the stack. |
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
@@ -774,6 +818,7 @@ |
__ j(not_equal, &fixed_array); |
// We got a map in register eax. Get the enumeration cache from it. |
+ __ bind(&use_cache); |
__ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
__ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |