From bd2fb51375f3a3cdee7248c20ee47e71f07e24f7 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Thu, 24 Feb 2011 11:39:27 +0000 Subject: [PATCH] ARM: Port r5445 r5445: Implement for-in cache validity checking in the full codegen on IA-32. Review URL: http://codereview.chromium.org/6581031 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6930 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 66 +++++++++++++++++++++++++++++++++++++++---- src/ia32/full-codegen-ia32.cc | 2 +- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index fea9a8c..5ce47a8 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -880,6 +880,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 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 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ 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 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ 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 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ 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)); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 3cdca4c..1a064bf 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -895,7 +895,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ cmp(edx, Factory::empty_descriptor_array()); __ j(equal, &call_runtime); - // Check that there in an enum cache in the non-empty instance + // Check that there is 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)); -- 2.7.4