Just grow elements if they happen to be at the edge of new space.
authorantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 15:16:04 +0000 (15:16 +0000)
committerantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Mar 2010 15:16:04 +0000 (15:16 +0000)
Review URL: http://codereview.chromium.org/945002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4133 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ia32/stub-cache-ia32.cc
test/mjsunit/array-push.js

index 902a5b81065a0ecfef42f537c49b9b951f110475..e554a31c7166b3bd8055ac8253c48f213ae6a9d9 100644 (file)
@@ -1251,7 +1251,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
     __ j(not_equal, &miss);
 
     if (argc == 1) {  // Otherwise fall through to call builtin.
-      Label call_builtin, exit, with_rset_update;
+      Label call_builtin, exit, with_rset_update,
+            attempt_to_grow_elements, finish_push;
 
       // Get the array's length into eax and calculate new length.
       __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset));
@@ -1263,9 +1264,9 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
       __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
       __ SmiTag(ecx);
 
-      // Check if we could survive without allocation, go to builtin otherwise.
+      // Check if we could survive without allocation.
       __ cmp(eax, Operand(ecx));
-      __ j(greater, &call_builtin);
+      __ j(greater, &attempt_to_grow_elements);
 
       // Save new length.
       __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
@@ -1277,6 +1278,8 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
       __ mov(ecx, Operand(esp, argc * kPointerSize));
       __ mov(Operand(edx, 0), ecx);
 
+      __ bind(&finish_push);
+
       // Check if value is a smi.
       __ test(ecx, Immediate(kSmiTagMask));
       __ j(not_zero, &with_rset_update);
@@ -1292,6 +1295,45 @@ Object* CallStubCompiler::CompileArrayPushCall(Object* object,
       __ CallStub(&stub);
       __ ret((argc + 1) * kPointerSize);
 
+      __ bind(&attempt_to_grow_elements);
+      ExternalReference new_space_allocation_top =
+          ExternalReference::new_space_allocation_top_address();
+      ExternalReference new_space_allocation_limit =
+          ExternalReference::new_space_allocation_limit_address();
+
+      const int kAllocationDelta = 4;
+      // Load top.
+      __ mov(ecx, Operand::StaticVariable(new_space_allocation_top));
+
+      // Check if it's the end of elements.
+      __ lea(edx, FieldOperand(ebx,
+                               eax, times_half_pointer_size,
+                               FixedArray::kHeaderSize - argc * kPointerSize));
+      __ cmp(edx, Operand(ecx));
+      __ j(not_equal, &call_builtin);
+      __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize));
+      __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
+      __ j(greater, &call_builtin);
+
+      // We fit and could grow elements.
+      __ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
+      __ mov(ecx, Operand(esp, argc * kPointerSize));
+      __ mov(Operand(edx, 0), ecx);
+      for (int i = 1; i < kAllocationDelta; i++) {
+        __ mov(Operand(edx, i * kPointerSize),
+               Immediate(Factory::undefined_value()));
+      }
+
+      // Restore receiver to edx as finish sequence assumes it's here.
+      __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
+
+      // Increment element's and array's sizes.
+      __ add(FieldOperand(ebx, FixedArray::kLengthOffset),
+             Immediate(kAllocationDelta));
+      __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax);
+
+      __ jmp(&finish_push);
+
       __ bind(&call_builtin);
     }
 
index a3168337d4bd057a72bb5d8df7cc80b096b30fc0..baccf000c4708cb2c69eaac50ef0f966f5a8cbe3 100644 (file)
       "after .push(22, 23, 24, 25, 26, 27, 28)");
   }
 })();
+
+// Excerises various pushes to the array at the end of new space.
+(function() {
+  var a = undefined;
+  for (var i = 0; i < 7; i++) {
+    a = [];
+    assertEquals(1, a.push(1));
+    assertEquals(2, a.push(2));
+    assertEquals(3, a.push(3));
+    assertEquals(4, a.push(4));
+    assertEquals(5, a.push(5));
+    assertEquals(6, a.push(6));
+    assertEquals(7, a.push(7));
+    assertEquals(8, a.push(8));
+    assertEquals(9, a.push(9));
+    assertEquals(10, a.push(10));
+    assertEquals(11, a.push(11));
+    assertEquals(12, a.push(12));
+    assertEquals(13, a.push(13));
+    assertEquals(14, a.push(14));
+    assertEquals(15, a.push(15));
+    assertEquals(16, a.push(16));
+    assertEquals(17, a.push(17));
+    assertEquals(18, a.push(18));
+    assertEquals(19, a.push(19));
+    assertEquals(20, a.push(20));
+    assertEquals(21, a.push(21));
+    assertEquals(22, a.push(22));
+    assertEquals(23, a.push(23));
+    assertEquals(24, a.push(24));
+    assertEquals(25, a.push(25));
+    assertEquals(26, a.push(26));
+    assertEquals(27, a.push(27));
+    assertEquals(28, a.push(28));
+    assertEquals(29, a.push(29));
+  }
+})();