Porting r9392 to x64 (smi-only arrays).
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 23 Sep 2011 14:19:04 +0000 (14:19 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 23 Sep 2011 14:19:04 +0000 (14:19 +0000)
Review URL: http://codereview.chromium.org/7992003

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

src/ia32/stub-cache-ia32.cc
src/x64/full-codegen-x64.cc
src/x64/ic-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
src/x64/stub-cache-x64.cc
test/mjsunit/element-kind.js

index b4eff5a..addf9e1 100644 (file)
@@ -3936,7 +3936,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 
   if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
     __ JumpIfNotSmi(eax, &miss_force_generic);
-    // ecx is a smi, don't use times_half_pointer_size istead of
+    // ecx is a smi, use times_half_pointer_size instead of
     // times_pointer_size
     __ mov(FieldOperand(edi,
                         ecx,
@@ -3945,7 +3945,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   } else {
     ASSERT(elements_kind == FAST_ELEMENTS);
     // Do the store and update the write barrier.
-    // ecx is a smi, don't use times_half_pointer_size istead of
+    // ecx is a smi, use times_half_pointer_size instead of
     // times_pointer_size
     __ lea(ecx, FieldOperand(edi,
                              ecx,
index 2f85e2f..1d9b8ff 100644 (file)
@@ -1455,13 +1455,25 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
     VisitForAccumulatorValue(subexpr);
 
     // Store the subexpression value in the array's elements.
-    __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
-    __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
+    __ movq(r8, Operand(rsp, 0));  // Copy of array literal.
+    __ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset));
     int offset = FixedArray::kHeaderSize + (i * kPointerSize);
     __ movq(FieldOperand(rbx, offset), result_register());
 
+    Label no_map_change;
+    __ JumpIfSmi(result_register(), &no_map_change);
     // Update the write barrier for the array store.
-    __ RecordWriteField(rbx, offset, result_register(), rcx, kDontSaveFPRegs);
+    __ RecordWriteField(rbx, offset, result_register(), rcx,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
+    if (FLAG_smi_only_arrays) {
+      __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
+      __ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear);
+      __ push(r8);
+      __ CallRuntime(Runtime::kNonSmiElementStored, 1);
+    }
+    __ bind(&no_map_change);
 
     PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
   }
index 359b595..514015a 100644 (file)
@@ -692,14 +692,22 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
   // rax: value
   // rbx: receiver's elements array (a FixedArray)
   // rcx: index
+
   Label non_smi_value;
+  __ JumpIfNotSmi(rax, &non_smi_value);
+  // It's irrelevant whether array is smi-only or not when writing a smi.
   __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
           rax);
-  __ JumpIfNotSmi(rax, &non_smi_value, Label::kNear);
   __ ret(0);
+
   __ bind(&non_smi_value);
-  // Slow case that needs to retain rcx for use by RecordWrite.
-  // Update write barrier for the elements array address.
+  if (FLAG_smi_only_arrays) {
+    // Writing a non-smi, check whether array allows non-smi elements.
+    __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
+    __ CheckFastObjectElements(rdi, &slow, Label::kNear);
+  }
+  __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+          rax);
   __ movq(rdx, rax);
   __ lea(rcx,
          FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize));
index b73e854..d586b0a 100644 (file)
@@ -2656,6 +2656,30 @@ void MacroAssembler::CheckFastElements(Register map,
 }
 
 
+void MacroAssembler::CheckFastObjectElements(Register map,
+                                             Label* fail,
+                                             Label::Distance distance) {
+  STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_ELEMENTS == 1);
+  cmpb(FieldOperand(map, Map::kBitField2Offset),
+       Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+  j(below_equal, fail, distance);
+  cmpb(FieldOperand(map, Map::kBitField2Offset),
+       Immediate(Map::kMaximumBitField2FastElementValue));
+  j(above, fail, distance);
+}
+
+
+void MacroAssembler::CheckFastSmiOnlyElements(Register map,
+                                              Label* fail,
+                                              Label::Distance distance) {
+  STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS == 0);
+  cmpb(FieldOperand(map, Map::kBitField2Offset),
+       Immediate(Map::kMaximumBitField2FastSmiOnlyElementValue));
+  j(above, fail, distance);
+}
+
+
 void MacroAssembler::CheckMap(Register obj,
                               Handle<Map> map,
                               Label* fail,
index d681192..db82785 100644 (file)
@@ -847,6 +847,18 @@ class MacroAssembler: public Assembler {
                          Label* fail,
                          Label::Distance distance = Label::kFar);
 
+  // Check if a map for a JSObject indicates that the object can have both smi
+  // and HeapObject elements.  Jump to the specified label if it does not.
+  void CheckFastObjectElements(Register map,
+                               Label* fail,
+                               Label::Distance distance = Label::kFar);
+
+  // Check if a map for a JSObject indicates that the object has fast smi only
+  // elements.  Jump to the specified label if it does not.
+  void CheckFastSmiOnlyElements(Register map,
+                                Label* fail,
+                                Label::Distance distance = Label::kFar);
+
   // Check if the map of an object is equal to a specified map and
   // branch to label if not. Skip the smi check if not required
   // (object is known to be a heap object)
index 584c549..3819c1d 100644 (file)
@@ -1442,28 +1442,42 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
       __ cmpl(rax, rcx);
       __ j(greater, &attempt_to_grow_elements);
 
+      // Check if value is a smi.
+      __ movq(rcx, Operand(rsp, argc * kPointerSize));
+      __ JumpIfNotSmi(rcx, &with_write_barrier);
+
       // Save new length.
       __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
 
       // Push the element.
-      __ movq(rcx, Operand(rsp, argc * kPointerSize));
       __ lea(rdx, FieldOperand(rbx,
                                rax, times_pointer_size,
                                FixedArray::kHeaderSize - argc * kPointerSize));
       __ movq(Operand(rdx, 0), rcx);
 
-      // Check if value is a smi.
       __ Integer32ToSmi(rax, rax);  // Return new length as smi.
-
-      __ JumpIfNotSmi(rcx, &with_write_barrier);
-
       __ ret((argc + 1) * kPointerSize);
 
       __ bind(&with_write_barrier);
 
+      if (FLAG_smi_only_arrays) {
+        __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
+        __ CheckFastObjectElements(rdi, &call_builtin);
+      }
+
+      // Save new length.
+      __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax);
+
+      // Push the element.
+      __ lea(rdx, FieldOperand(rbx,
+                               rax, times_pointer_size,
+                               FixedArray::kHeaderSize - argc * kPointerSize));
+      __ movq(Operand(rdx, 0), rcx);
+
       __ RecordWrite(
           rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 
+      __ Integer32ToSmi(rax, rax);  // Return new length as smi.
       __ ret((argc + 1) * kPointerSize);
 
       __ bind(&attempt_to_grow_elements);
@@ -1471,6 +1485,17 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
         __ jmp(&call_builtin);
       }
 
+      __ movq(rdi, Operand(rsp, argc * kPointerSize));
+      if (FLAG_smi_only_arrays) {
+        // Growing elements that are SMI-only requires special handling in case
+        // the new element is non-Smi. For now, delegate to the builtin.
+        Label no_fast_elements_check;
+        __ JumpIfSmi(rdi, &no_fast_elements_check);
+        __ movq(rsi, FieldOperand(rdx, HeapObject::kMapOffset));
+        __ CheckFastObjectElements(rsi, &call_builtin, Label::kFar);
+        __ bind(&no_fast_elements_check);
+      }
+
       ExternalReference new_space_allocation_top =
           ExternalReference::new_space_allocation_top_address(isolate());
       ExternalReference new_space_allocation_limit =
@@ -1494,10 +1519,9 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
 
       // We fit and could grow elements.
       __ Store(new_space_allocation_top, rcx);
-      __ movq(rcx, Operand(rsp, argc * kPointerSize));
 
       // Push the argument...
-      __ movq(Operand(rdx, 0), rcx);
+      __ movq(Operand(rdx, 0), rdi);
       // ... and fill the rest with holes.
       __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
       for (int i = 1; i < kAllocationDelta; i++) {
@@ -1509,7 +1533,7 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
       // tell the incremental marker to rescan the object that we just grew.  We
       // don't need to worry about the holes because they are in old space and
       // already marked black.
-      __ RecordWrite(rbx, rdx, rcx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
+      __ RecordWrite(rbx, rdx, rdi, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
 
       // Restore receiver to rdx as finish sequence assumes it's here.
       __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
@@ -3699,13 +3723,19 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 
   // Do the store and update the write barrier.
   __ SmiToInteger32(rcx, rcx);
-  __ lea(rcx,
-         FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
-  __ movq(Operand(rcx, 0), rax);
-  // Make sure to preserve the value in register rax.
-  __ movq(rdx, rax);
-  ASSERT(elements_kind == FAST_ELEMENTS);
-  __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs);
+  if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+    __ JumpIfNotSmi(rax, &miss_force_generic);
+    __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize),
+            rax);
+  } else {
+    ASSERT(elements_kind == FAST_ELEMENTS);
+    __ lea(rcx,
+           FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize));
+    __ movq(Operand(rcx, 0), rax);
+    // Make sure to preserve the value in register rax.
+    __ movq(rdx, rax);
+    __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs);
+  }
 
   // Done.
   __ ret(0);
index 1949857..0159f5a 100644 (file)
@@ -47,7 +47,7 @@ var element_kind = {
 }
 
 // We expect an object to only be of one element kind.
-function assertKind(expected, obj){
+function assertKind(expected, obj) {
   if (support_smi_only_arrays) {
     assertEquals(expected == element_kind.fast_smi_only_elements,
                  %HasFastSmiOnlyElements(obj));
@@ -100,7 +100,7 @@ assertKind(element_kind.fast_smi_only_elements, too);
 // Make sure the element kind transitions from smionly when a non-smi is stored.
 var you = new Array();
 assertKind(element_kind.fast_smi_only_elements, you);
-for(i = 0; i < 1337; i++) {
+for (var i = 0; i < 1337; i++) {
   var val = i;
   if (i == 1336) {
     assertKind(element_kind.fast_smi_only_elements, you);
@@ -110,10 +110,11 @@ for(i = 0; i < 1337; i++) {
 }
 assertKind(element_kind.fast_elements, you);
 
-assertKind(element_kind.dictionary_elements, new Array(0xC0C0A));
-
-// fast_double_elements not yet available
+assertKind(element_kind.dictionary_elements, new Array(0xDECAF));
 
+var fast_double_array = new Array(0xDECAF);
+for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
+assertKind(element_kind.fast_double_elements, fast_double_array);
 
 assertKind(element_kind.external_byte_elements,           new Int8Array(9001));
 assertKind(element_kind.external_unsigned_byte_elements,  new Uint8Array(007));