Porting r9605 to x64 (elements kind conversion in generated code).
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 17 Oct 2011 10:44:47 +0000 (10:44 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 17 Oct 2011 10:44:47 +0000 (10:44 +0000)
Review URL: http://codereview.chromium.org/8271007

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

src/code-stubs.cc
src/ia32/code-stubs-ia32.cc
src/x64/code-stubs-x64.cc
src/x64/ic-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/mjsunit/elements-transition.js

index 78585d8..a298bc4 100644 (file)
@@ -416,7 +416,7 @@ bool ToBooleanStub::Types::CanBeUndetectable() const {
 
 
 void FastElementsConversionStub::Generate(MacroAssembler* masm) {
-#if defined(V8_TARGET_ARCH_IA32)
+#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64)
   if (to_ == FAST_ELEMENTS) {
     if (from_ == FAST_SMI_ONLY_ELEMENTS) {
       GenerateSmiOnlyToObject(masm);
@@ -436,7 +436,7 @@ void FastElementsConversionStub::Generate(MacroAssembler* masm) {
   }
 #else
   KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
-#endif  // V8_TARGET_ARCH_IA32
+#endif  // V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
 }
 
 } }  // namespace v8::internal
index 0cc21c4..c22b45f 100644 (file)
@@ -7061,9 +7061,8 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
                       OMIT_SMI_CHECK);
 
   __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
-  // Convert and copy elements
-  // esi: source FixedArray
-  // edi: number of elements to convert/copy
+
+  // Prepare for conversion loop.
   ExternalReference canonical_the_hole_nan_reference =
       ExternalReference::address_of_the_hole_nan();
   XMMRegister the_hole_nan = xmm1;
@@ -7073,6 +7072,18 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
               Operand::StaticVariable(canonical_the_hole_nan_reference));
   }
   __ jmp(&entry);
+
+  // Call into runtime if GC is required.
+  __ bind(&gc_required);
+  // Restore registers before jumping into runtime.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ pop(ebx);
+  __ pop(eax);
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+
+  // Convert and copy elements
+  // esi: source FixedArray
+  // edi: number of elements to convert/copy
   __ bind(&loop);
   __ sub(edi, Immediate(Smi::FromInt(1)));
   __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
@@ -7110,7 +7121,6 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
   __ test(edi, edi);
   __ j(not_zero, &loop);
 
-  Label done;
   __ pop(ebx);
   __ pop(eax);
   // eax: value
@@ -7126,15 +7136,6 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
                       OMIT_SMI_CHECK);
   // Restore esi.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ jmp(&done, Label::kNear);
-
-  __ bind(&gc_required);
-  // Restore registers before jumping into runtime.
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ pop(ebx);
-  __ pop(eax);
-  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
-  __ bind(&done);
 }
 
 
@@ -7167,10 +7168,19 @@ void FastElementsConversionStub::GenerateDoubleToObject(
   __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
   __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
 
+  __ jmp(&entry);
+
+  // Call into runtime if GC is required.
+  __ bind(&gc_required);
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ pop(ebx);
+  __ pop(edx);
+  __ pop(eax);
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+
   // Box doubles into heap numbers.
   // edi: source FixedDoubleArray
   // eax: destination FixedArray
-  __ jmp(&entry);
   __ bind(&loop);
   __ sub(ebx, Immediate(Smi::FromInt(1)));
   // ebx: index of current element (smi-tagged)
@@ -7200,9 +7210,9 @@ void FastElementsConversionStub::GenerateDoubleToObject(
                       kDontSaveFPRegs,
                       EMIT_REMEMBERED_SET,
                       OMIT_SMI_CHECK);
-  __ jmp(&entry);
+  __ jmp(&entry, Label::kNear);
 
-  // Replace the-hole nan with the-hole pointer.
+  // Replace the-hole NaN with the-hole pointer.
   __ bind(&convert_hole);
   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
          masm->isolate()->factory()->the_hole_value());
@@ -7235,18 +7245,8 @@ void FastElementsConversionStub::GenerateDoubleToObject(
                       OMIT_SMI_CHECK);
 
   // Restore registers.
-  Label done;
   __ pop(eax);
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ jmp(&done, Label::kNear);
-
-  __ bind(&gc_required);
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ pop(ebx);
-  __ pop(edx);
-  __ pop(eax);
-  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
-  __ bind(&done);
 }
 
 #undef __
index 7d41ffe..9dfd169 100644 (file)
@@ -5665,6 +5665,12 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
   { rbx, rdx, rcx, EMIT_REMEMBERED_SET},
   // KeyedStoreStubCompiler::GenerateStoreFastElement.
   { rdi, rdx, rcx, EMIT_REMEMBERED_SET},
+  // FastElementsConversionStub::GenerateSmiOnlyToObject
+  // and FastElementsConversionStub::GenerateDoubleToObject
+  { rdx, rbx, rdi, EMIT_REMEMBERED_SET},
+  // FastElementsConversionStub::GenerateDoubleToObject
+  { rax, r11, r15, EMIT_REMEMBERED_SET},
+  { rdx, rax, rdi, EMIT_REMEMBERED_SET},
   // Null termination.
   { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
 };
@@ -5913,6 +5919,181 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
 }
 
 
+void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rbx    : target map
+  //  -- rcx    : key
+  //  -- rdx    : receiver
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  // Set transitioned map.
+  __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+  __ RecordWriteField(rdx,
+                      HeapObject::kMapOffset,
+                      rbx,
+                      rdi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+void FastElementsConversionStub::GenerateSmiOnlyToDouble(
+    MacroAssembler* masm, StrictModeFlag strict_mode) {
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rbx    : target map
+  //  -- rcx    : key
+  //  -- rdx    : receiver
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  // Set transitioned map.
+  __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+  __ RecordWriteField(rdx,
+                      HeapObject::kMapOffset,
+                      rbx,
+                      rdi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  // Set backing store's map
+  __ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
+  __ movq(FieldOperand(r8, HeapObject::kMapOffset), rdi);
+
+  // Convert smis to doubles and holes to hole NaNs.  Since FixedArray and
+  // FixedDoubleArray do not differ in size, we do not allocate a new array.
+  STATIC_ASSERT(FixedDoubleArray::kLengthOffset == FixedArray::kLengthOffset);
+  STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
+  __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
+  // r8 : elements array
+  // r9 : elements array length
+  Label loop, entry, convert_hole;
+  __ movq(r15, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+  // r15: the-hole NaN
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ decq(r9);
+  __ movq(rbx,
+          FieldOperand(r8, r9, times_8, FixedArray::kHeaderSize));
+  // r9 : current element's index
+  // rbx: current element (smi-tagged)
+  __ JumpIfNotSmi(rbx, &convert_hole);
+  __ SmiToInteger32(rbx, rbx);
+  __ cvtlsi2sd(xmm0, rbx);
+  __ movsd(FieldOperand(r8, r9, times_8, FixedDoubleArray::kHeaderSize),
+           xmm0);
+  __ jmp(&entry);
+  __ bind(&convert_hole);
+  __ movq(FieldOperand(r8, r9, times_8, FixedDoubleArray::kHeaderSize), r15);
+  __ bind(&entry);
+  __ testq(r9, r9);
+  __ j(not_zero, &loop);
+}
+
+
+void FastElementsConversionStub::GenerateDoubleToObject(
+    MacroAssembler* masm, StrictModeFlag strict_mode) {
+  // ----------- S t a t e -------------
+  //  -- rax    : value
+  //  -- rbx    : target map
+  //  -- rcx    : key
+  //  -- rdx    : receiver
+  //  -- rsp[0] : return address
+  // -----------------------------------
+  Label loop, entry, convert_hole, gc_required;
+  __ push(rax);
+
+  __ movq(r8, FieldOperand(rdx, JSObject::kElementsOffset));
+  __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
+  // r8 : source FixedDoubleArray
+  // r9 : number of elements
+  __ lea(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
+  __ AllocateInNewSpace(rdi, rax, r14, r15, &gc_required, TAG_OBJECT);
+  // rax: destination FixedArray
+  __ LoadRoot(rdi, Heap::kFixedArrayMapRootIndex);
+  __ movq(FieldOperand(rax, HeapObject::kMapOffset), rdi);
+  __ Integer32ToSmi(r14, r9);
+  __ movq(FieldOperand(rax, FixedArray::kLengthOffset), r14);
+
+  // Prepare for conversion loop.
+  __ movq(rsi, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+  __ Move(rdi, masm->isolate()->factory()->the_hole_value());
+  // rsi: the-hole NaN
+  // rdi: pointer to the-hole
+  __ jmp(&entry);
+
+  // Call into runtime if GC is required.
+  __ bind(&gc_required);
+  __ pop(rax);
+  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+
+  // Box doubles into heap numbers.
+  __ bind(&loop);
+  __ decq(r9);
+  __ movq(r14, FieldOperand(r8,
+                            r9,
+                            times_pointer_size,
+                            FixedDoubleArray::kHeaderSize));
+  // r9 : current element's index
+  // r14: current element
+  __ cmpq(r14, rsi);
+  __ j(equal, &convert_hole);
+
+  // Non-hole double, copy value into a heap number.
+  __ AllocateHeapNumber(r11, r15, &gc_required);
+  // r11: new heap number
+  __ movq(FieldOperand(r11, HeapNumber::kValueOffset), r14);
+  __ movq(FieldOperand(rax,
+                       r9,
+                       times_pointer_size,
+                       FixedArray::kHeaderSize),
+          r11);
+  __ movq(r15, r9);
+  __ RecordWriteArray(rax,
+                      r11,
+                      r15,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ jmp(&entry, Label::kNear);
+
+  // Replace the-hole NaN with the-hole pointer.
+  __ bind(&convert_hole);
+  __ movq(FieldOperand(rax,
+                       r9,
+                       times_pointer_size,
+                       FixedArray::kHeaderSize),
+          rdi);
+
+  __ bind(&entry);
+  __ testq(r9, r9);
+  __ j(not_zero, &loop);
+
+  // Set transitioned map.
+  __ movq(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
+  __ RecordWriteField(rdx,
+                      HeapObject::kMapOffset,
+                      rbx,
+                      rdi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  // Replace receiver's backing store with newly created and filled FixedArray.
+  __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rax);
+  __ RecordWriteField(rdx,
+                      JSObject::kElementsOffset,
+                      rax,
+                      rdi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ pop(rax);
+  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+}
+
 #undef __
 
 } }  // namespace v8::internal
index c79d44d..129226e 100644 (file)
@@ -712,12 +712,11 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
   // Writing a non-smi, check whether array allows non-smi elements.
   // r9: receiver's map
   __ CheckFastObjectElements(r9, &slow, Label::kNear);
-  __ lea(rcx,
-         FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize));
-  __ movq(Operand(rcx, 0), rax);
-  __ movq(rdx, rax);
-  __ RecordWrite(
-      rbx, rcx, rdx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
+          rax);
+  __ movq(rdx, rax);  // Preserve the value which is returned.
+  __ RecordWriteArray(
+      rbx, rax, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   __ ret(0);
 
   __ bind(&fast_double_with_map_check);
index 7fe6d58..a11ac1d 100644 (file)
@@ -326,6 +326,40 @@ void MacroAssembler::RecordWriteField(
 }
 
 
+void MacroAssembler::RecordWriteArray(Register object,
+                                      Register value,
+                                      Register index,
+                                      SaveFPRegsMode save_fp,
+                                      RememberedSetAction remembered_set_action,
+                                      SmiCheck smi_check) {
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of Smis.
+  Label done;
+
+  // Skip barrier if writing a smi.
+  if (smi_check == INLINE_SMI_CHECK) {
+    JumpIfSmi(value, &done);
+  }
+
+  // Array access: calculate the destination address. Index is not a smi.
+  Register dst = index;
+  lea(dst, Operand(object, index, times_pointer_size,
+                   FixedArray::kHeaderSize - kHeapObjectTag));
+
+  RecordWrite(
+      object, dst, value, save_fp, remembered_set_action, OMIT_SMI_CHECK);
+
+  bind(&done);
+
+  // Clobber clobbered input registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    movq(value, Immediate(BitCast<int64_t>(kZapValue)));
+    movq(index, Immediate(BitCast<int64_t>(kZapValue)));
+  }
+}
+
+
 void MacroAssembler::RecordWrite(Register object,
                                  Register address,
                                  Register value,
index 7e0ba00..526ea7f 100644 (file)
@@ -256,8 +256,8 @@ class MacroAssembler: public Assembler {
 
   // Notify the garbage collector that we wrote a pointer into a fixed array.
   // |array| is the array being stored into, |value| is the
-  // object being stored.  |index| is the array index represented as a
-  // Smi. All registers are clobbered by the operation RecordWriteArray
+  // object being stored.  |index| is the array index represented as a non-smi.
+  // All registers are clobbered by the operation RecordWriteArray
   // filters out smis so it does not update the write barrier if the
   // value is a smi.
   void RecordWriteArray(
index f198324..ab3c690 100644 (file)
@@ -69,6 +69,9 @@ if (support_smi_only_arrays) {
         assertEquals(2*i+1, array_2[i]);
       }
     }
+
+    assertEquals(length, array_1.length);
+    assertEquals(length, array_2.length);
   }
 
   test(false, false, function(a,i,v){ a[i] = v; }, 100);