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