From: yangguo@chromium.org Date: Mon, 17 Oct 2011 10:44:47 +0000 (+0000) Subject: Porting r9605 to x64 (elements kind conversion in generated code). X-Git-Tag: upstream/4.7.83~18198 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=92fdeff12500d4f7f45a542ecd45503692b5bfa6;p=platform%2Fupstream%2Fv8.git Porting r9605 to x64 (elements kind conversion in generated code). Review URL: http://codereview.chromium.org/8271007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9655 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 78585d8..a298bc4 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -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 diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 0cc21c4..c22b45f 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -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 __ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 7d41ffe..9dfd169 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -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(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(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 diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index c79d44d..129226e 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -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); diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 7fe6d58..a11ac1d 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -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(kZapValue))); + movq(index, Immediate(BitCast(kZapValue))); + } +} + + void MacroAssembler::RecordWrite(Register object, Register address, Register value, diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 7e0ba00..526ea7f 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -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( diff --git a/test/mjsunit/elements-transition.js b/test/mjsunit/elements-transition.js index f198324..ab3c690 100644 --- a/test/mjsunit/elements-transition.js +++ b/test/mjsunit/elements-transition.js @@ -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);