Revision: 3407
Author: [email protected]
Date: Thu Dec  3 02:24:16 2009
Log: Move for-in cache validity check to generated code.
Review URL: http://codereview.chromium.org/464002
http://code.google.com/p/v8/source/detail?r=3407

Modified:
  /branches/bleeding_edge/src/arm/codegen-arm.cc
  /branches/bleeding_edge/src/ia32/codegen-ia32.cc
  /branches/bleeding_edge/src/x64/codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Wed Dec  2 23:56:21 2009
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Dec  3 02:24:16 2009
@@ -1775,19 +1775,77 @@

    jsobject.Bind();
    // Get the set of properties (as a FixedArray or Map).
-  frame_->EmitPush(r0);  // duplicate the object being enumerated
-  frame_->EmitPush(r0);
+  // r0: value to be iterated over
+  frame_->EmitPush(r0);  // Push the object being iterated over.
+
+  // 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.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ mov(r1, Operand(r0));
+  loop.Bind();
+  // Check that there are no elements.
+  __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
+  __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
+  __ cmp(r2, r4);
+  call_runtime.Branch(ne);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in r3 for the subsequent
+  // prototype load.
+  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(r2, FieldMemOperand(r3, Map::kInstanceDescriptorsOffset));
+  __ LoadRoot(ip, Heap::kEmptyDescriptorArrayRootIndex);
+  __ cmp(r2, ip);
+  call_runtime.Branch(eq);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ ldr(r2, FieldMemOperand(r2,  
DescriptorArray::kEnumerationIndexOffset));
+  __ tst(r2, Operand(kSmiTagMask));
+  call_runtime.Branch(eq);
+  // For all objects but the receiver, check that the cache is empty.
+  // r4: empty fixed array root.
+  __ cmp(r1, r0);
+  check_prototype.Branch(eq);
+  __ ldr(r2, FieldMemOperand(r2,  
DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ cmp(r2, r4);
+  call_runtime.Branch(ne);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ ldr(r1, FieldMemOperand(r3, Map::kPrototypeOffset));
+  __ LoadRoot(ip, Heap::kNullValueRootIndex);
+  __ cmp(r1, ip);
+  loop.Branch(ne);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
+  frame_->EmitPush(r0);  // push the object (slot 4) for the runtime call
    frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);

-  // If we got a Map, we can do a fast modification check.
-  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
+  // r0: map or fixed array (result from call to
+  // Runtime::kGetPropertyNamesFast)
    __ mov(r2, Operand(r0));
    __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
    __ LoadRoot(ip, Heap::kMetaMapRootIndex);
    __ cmp(r1, ip);
    fixed_array.Branch(ne);

+  use_cache.Bind();
    // Get enum cache
+  // r0: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
    __ mov(r1, Operand(r0));
    __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
    __ ldr(r1, FieldMemOperand(r1,  
DescriptorArray::kEnumerationIndexOffset));
@@ -6396,7 +6454,7 @@
    __ b(eq, &adaptor);

    // Check index against formal parameters count limit passed in
-  // through register eax. Use unsigned comparison to get negative
+  // through register r0. Use unsigned comparison to get negative
    // check for free.
    __ cmp(r1, r0);
    __ b(cs, &slow);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Wed Dec  2 23:56:21  
2009
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Thu Dec  3 02:24:16  
2009
@@ -3056,13 +3056,59 @@
    jsobject.Bind();
    // Get the set of properties (as a FixedArray or Map).
    // eax: value to be iterated over
-  frame_->EmitPush(eax);  // push the object being iterated over (slot 4)
-
+  frame_->EmitPush(eax);  // Push the object being iterated over.
+
+  // 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.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ mov(ecx, eax);
+  loop.Bind();
+  // Check that there are no elements.
+  __ mov(edx, FieldOperand(ecx, JSObject::kElementsOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+  call_runtime.Branch(not_equal);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in ebx for the subsequent
+  // prototype load.
+  __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
+  __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_descriptor_array()));
+  call_runtime.Branch(equal);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset));
+  __ test(edx, Immediate(kSmiTagMask));
+  call_runtime.Branch(zero);
+  // For all objects but the receiver, check that the cache is empty.
+  __ cmp(ecx, Operand(eax));
+  check_prototype.Branch(equal);
+  __ mov(edx, FieldOperand(edx,  
DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ cmp(Operand(edx), Immediate(Factory::empty_fixed_array()));
+  call_runtime.Branch(not_equal);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
+  __ cmp(Operand(ecx), Immediate(Factory::null_value()));
+  loop.Branch(not_equal);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
    frame_->EmitPush(eax);  // push the Object (slot 4) for the runtime call
    frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);

-  // If we got a Map, we can do a fast modification check.
-  // Otherwise, we got a FixedArray, and we have to do a slow check.
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
    // eax: map or fixed array (result from call to
    // Runtime::kGetPropertyNamesFast)
    __ mov(edx, Operand(eax));
@@ -3070,9 +3116,13 @@
    __ cmp(ecx, Factory::meta_map());
    fixed_array.Branch(not_equal);

+  use_cache.Bind();
    // Get enum cache
-  // eax: map (result from call to Runtime::kGetPropertyNamesFast)
+  // eax: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
    __ mov(ecx, Operand(eax));
+
    __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
    // Get the bridge array held in the enumeration index field.
    __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Wed Dec  2 23:56:21 2009
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Thu Dec  3 02:24:16 2009
@@ -1662,8 +1662,54 @@
    jsobject.Bind();
    // Get the set of properties (as a FixedArray or Map).
    // rax: value to be iterated over
-  frame_->EmitPush(rax);  // push the object being iterated over (slot 4)
-
+  frame_->EmitPush(rax);  // Push the object being iterated over.
+
+
+  // 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.
+  JumpTarget call_runtime;
+  JumpTarget loop(JumpTarget::BIDIRECTIONAL);
+  JumpTarget check_prototype;
+  JumpTarget use_cache;
+  __ movq(rcx, rax);
+  loop.Bind();
+  // Check that there are no elements.
+  __ movq(rdx, FieldOperand(rcx, JSObject::kElementsOffset));
+  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
+  call_runtime.Branch(not_equal);
+  // Check that instance descriptors are not empty so that we can
+  // check for an enum cache.  Leave the map in ebx for the subsequent
+  // prototype load.
+  __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
+  __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
+  __ CompareRoot(rdx, Heap::kEmptyDescriptorArrayRootIndex);
+  call_runtime.Branch(equal);
+  // Check that there in an enum cache in the non-empty instance
+  // descriptors.  This is the case if the next enumeration index
+  // field does not contain a smi.
+  __ movq(rdx, FieldOperand(rdx,  
DescriptorArray::kEnumerationIndexOffset));
+  is_smi = masm_->CheckSmi(rdx);
+  call_runtime.Branch(is_smi);
+  // For all objects but the receiver, check that the cache is empty.
+  __ cmpq(rcx, rax);
+  check_prototype.Branch(equal);
+  __ movq(rdx, FieldOperand(rdx,  
DescriptorArray::kEnumCacheBridgeCacheOffset));
+  __ CompareRoot(rdx, Heap::kEmptyFixedArrayRootIndex);
+  call_runtime.Branch(not_equal);
+  check_prototype.Bind();
+  // Load the prototype from the map and loop if non-null.
+  __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
+  __ CompareRoot(rcx, Heap::kNullValueRootIndex);
+  loop.Branch(not_equal);
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
+  use_cache.Jump();
+
+  call_runtime.Bind();
+  // Call the runtime to get the property names for the object.
    frame_->EmitPush(rax);  // push the Object (slot 4) for the runtime call
    frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);

@@ -1676,8 +1722,11 @@
    __ CompareRoot(rcx, Heap::kMetaMapRootIndex);
    fixed_array.Branch(not_equal);

+  use_cache.Bind();
    // Get enum cache
-  // rax: map (result from call to Runtime::kGetPropertyNamesFast)
+  // rax: map (either the result from a call to
+  // Runtime::kGetPropertyNamesFast or has been fetched directly from
+  // the object)
    __ movq(rcx, rax);
    __ movq(rcx, FieldOperand(rcx, Map::kInstanceDescriptorsOffset));
    // Get the bridge array held in the enumeration index field.

-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to