Index: src/arm/full-codegen-arm.cc |
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc |
index 4ab158fea62e2388f89cc001615424bfbdde00c3..43e5c6a701fe44cb9337c23c46e2189db41f7a85 100644 |
--- a/src/arm/full-codegen-arm.cc |
+++ b/src/arm/full-codegen-arm.cc |
@@ -929,11 +929,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ bind(&done_convert); |
__ push(r0); |
+ // Check for proxies. |
+ Label call_runtime; |
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
+ __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE); |
+ __ b(le, &call_runtime); |
+ |
// 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; |
+ Label next; |
// Preload a couple of values used in the loop. |
Register empty_fixed_array_value = r6; |
__ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
@@ -1012,9 +1018,16 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ jmp(&loop); |
// We got a fixed array in register r0. Iterate through that. |
+ Label non_proxy; |
__ bind(&fixed_array); |
- __ mov(r1, Operand(Smi::FromInt(0))); // Map (0) - force slow check. |
- __ Push(r1, r0); |
+ __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check |
+ __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object |
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
+ __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); |
+ __ b(gt, &non_proxy); |
+ __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy |
+ __ bind(&non_proxy); |
+ __ Push(r1, r0); // Smi and array |
__ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); |
__ mov(r0, Operand(Smi::FromInt(0))); |
__ Push(r1, r0); // Fixed array length (as smi) and initial index. |
@@ -1031,18 +1044,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
__ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
- // Get the expected map from the stack or a zero map in the |
+ // Get the expected map from the stack or a smi in the |
// permanent slow case into register r2. |
__ ldr(r2, MemOperand(sp, 3 * kPointerSize)); |
// Check if the expected map still matches that of the enumerable. |
- // If not, we have to filter the key. |
+ // If not, we may have to filter the key. |
Label update_each; |
__ ldr(r1, MemOperand(sp, 4 * kPointerSize)); |
__ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset)); |
__ cmp(r4, Operand(r2)); |
__ b(eq, &update_each); |
+ // For proxies, no filtering is done. |
+ // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. |
+ __ cmp(r2, Operand(Smi::FromInt(0))); |
+ __ b(eq, &update_each); |
+ |
// Convert the entry to a string or (smi) 0 if it isn't a property |
// any more. If the property has been removed while iterating, we |
// just skip it. |