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
This commit is contained in:
parent
c8f8c69fd6
commit
bd2fb51375
@ -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));
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user