Index: src/x64/full-codegen-x64.cc |
=================================================================== |
--- src/x64/full-codegen-x64.cc (revision 6929) |
+++ src/x64/full-codegen-x64.cc (working copy) |
@@ -847,13 +847,17 @@ |
ForIn loop_statement(this, stmt); |
increment_loop_depth(); |
+ // Load null value as it is used several times below. |
+ Register null_value = rdi; |
+ __ 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. |
VisitForAccumulatorValue(stmt->enumerable()); |
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
__ j(equal, &exit); |
- __ CompareRoot(rax, Heap::kNullValueRootIndex); |
+ __ cmpq(rax, null_value); |
__ j(equal, &exit); |
// Convert the object to a JS object. |
@@ -867,12 +871,61 @@ |
__ bind(&done_convert); |
__ push(rax); |
- // 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; |
+ Register empty_fixed_array_value = r8; |
+ __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
+ Register empty_descriptor_array_value = r9; |
+ __ LoadRoot(empty_descriptor_array_value, |
+ Heap::kEmptyDescriptorArrayRootIndex); |
+ __ movq(rcx, rax); |
+ __ bind(&next); |
+ // Check that there are no elements. Register rcx contains the |
+ // current JS object we've reached through the prototype chain. |
+ __ cmpq(empty_fixed_array_value, |
+ FieldOperand(rcx, JSObject::kElementsOffset)); |
+ __ 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 rbx for the subsequent |
+ // prototype load. |
+ __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); |
+ __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset)); |
+ __ cmpq(rdx, empty_descriptor_array_value); |
+ __ j(equal, &call_runtime); |
+ |
+ // Check that there is an enum cache in the non-empty instance |
+ // descriptors (rdx). This is the case if the next enumeration |
+ // index field does not contain a smi. |
+ __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset)); |
+ __ JumpIfSmi(rdx, &call_runtime); |
+ |
+ // For all objects but the receiver, check that the cache is empty. |
+ NearLabel check_prototype; |
+ __ cmpq(rcx, rax); |
+ __ j(equal, &check_prototype); |
+ __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
+ __ cmpq(rdx, empty_fixed_array_value); |
+ __ j(not_equal, &call_runtime); |
+ |
+ // Load the prototype from the map and loop if non-null. |
+ __ bind(&check_prototype); |
+ __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); |
+ __ cmpq(rcx, 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. |
+ NearLabel use_cache; |
+ __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
+ __ jmp(&use_cache); |
+ |
// Get the set of properties to enumerate. |
+ __ bind(&call_runtime); |
__ push(rax); // Duplicate the enumerable object on the stack. |
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
@@ -885,6 +938,7 @@ |
__ j(not_equal, &fixed_array); |
// We got a map in register rax. Get the enumeration cache from it. |
+ __ bind(&use_cache); |
__ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); |
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); |
__ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |