From 8472de004b48799e184e1d295895907c9a62d9ad Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Wed, 19 Oct 2011 09:04:35 +0000 Subject: [PATCH] Porting r9605 to arm (elements kind conversion in generated code). Review URL: http://codereview.chromium.org/8329022 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9690 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/code-stubs-arm.cc | 249 ++++++++++++++++++++++++++++++++++++ src/arm/stub-cache-arm.cc | 4 +- src/code-stubs.cc | 4 - src/x64/code-stubs-x64.cc | 2 +- test/mjsunit/elements-transition.js | 26 ++-- 5 files changed, 268 insertions(+), 17 deletions(-) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 3afa76c..22f6a2e 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -6927,6 +6927,13 @@ struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { { r3, r1, r2, EMIT_REMEMBERED_SET }, // KeyedStoreStubCompiler::GenerateStoreFastElement. { r4, r2, r3, EMIT_REMEMBERED_SET }, + // FastElementsConversionStub::GenerateSmiOnlyToObject + // and FastElementsConversionStub::GenerateSmiOnlyToDouble + // and FastElementsConversionStub::GenerateDoubleToObject + { r2, r3, r9, EMIT_REMEMBERED_SET }, + // FastElementsConversionStub::GenerateDoubleToObject + { r6, r0, r3, EMIT_REMEMBERED_SET }, + { r2, r6, r9, EMIT_REMEMBERED_SET }, // Null termination. { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} }; @@ -7164,6 +7171,248 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker( } +void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + // Set transitioned map. + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasNotBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); +} + + +void FastElementsConversionStub::GenerateSmiOnlyToDouble( + MacroAssembler* masm, StrictModeFlag strict_mode) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + Label loop, entry, convert_hole, gc_required, fail; + bool vfp3_supported = CpuFeatures::IsSupported(VFP3); + + __ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset)); + // r4: source FixedArray + // r5: number of elements (smi-tagged) + + // Allocate new FixedDoubleArray. + __ mov(ip, Operand(FixedDoubleArray::kHeaderSize)); + __ add(ip, ip, Operand(r5, LSL, 2)); + __ AllocateInNewSpace(ip, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); + // r6: destination FixedDoubleArray, not tagged as heap object + __ LoadRoot(r9, Heap::kFixedDoubleArrayMapRootIndex); + __ str(r9, MemOperand(r6, HeapObject::kMapOffset)); + // Set destination FixedDoubleArray's length. + __ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset)); + // Update receiver's map. + __ push(lr); + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + // Replace receiver's backing store with newly created FixedDoubleArray. + __ add(r3, r6, Operand(kHeapObjectTag)); + __ str(r3, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ RecordWriteField(r2, + JSObject::kElementsOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ pop(lr); + + // Prepare for conversion loop. + __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + __ add(r6, r6, Operand(FixedDoubleArray::kHeaderSize)); + __ add(r4, r6, Operand(r5, LSL, 2)); + __ mov(r5, Operand(kHoleNanLower32)); + __ mov(r7, Operand(kHoleNanUpper32)); + // r3: begin of source FixedArray element fields, not tagged + // r4: end of destination FixedDoubleArray, not tagged + // r6: begin of FixedDoubleArray element fields, not tagged + // r5: kHoleNanLower32 + // r7: kHoleNanUpper32 + if (vfp3_supported) __ Push(r0, r1); + + __ b(&entry); + + // Call into runtime if GC is required. + __ bind(&gc_required); + KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode); + + // Convert and copy elements. + __ bind(&loop); + __ ldr(r9, MemOperand(r3, 4, PostIndex)); + // r9: current element + __ JumpIfNotSmi(r9, &convert_hole); + + // Normal smi, convert to double and store. + __ SmiUntag(r9); + if (vfp3_supported) { + CpuFeatures::Scope scope(VFP3); + __ vmov(s0, r9); + __ vcvt_f64_s32(d0, s0); + __ vstr(d0, r6, 0); + __ add(r6, r6, Operand(8)); + } else { + FloatingPointHelper::ConvertIntToDouble(masm, + r9, + FloatingPointHelper::kCoreRegisters, + d0, + r0, + r1, + ip, + s0); + __ str(r0, MemOperand(r6, 4, PostIndex)); // mantissa + __ str(r1, MemOperand(r6, 4, PostIndex)); // exponent + } + __ b(&entry); + + // Hole found, store the-hole NaN. + __ bind(&convert_hole); + __ str(r5, MemOperand(r6, 4, PostIndex)); // mantissa + __ str(r7, MemOperand(r6, 4, PostIndex)); // exponent + + __ bind(&entry); + __ cmp(r6, r4); + __ b(lt, &loop); + + if (vfp3_supported) __ Pop(r0, r1); +} + + +void FastElementsConversionStub::GenerateDoubleToObject( + MacroAssembler* masm, StrictModeFlag strict_mode) { + // ----------- S t a t e ------------- + // -- r0 : value + // -- r1 : key + // -- r2 : receiver + // -- lr : return address + // -- r3 : target map, scratch for subsequent call + // -- r4 : scratch (elements) + // ----------------------------------- + Label entry, loop, convert_hole, gc_required; + + __ push(lr); + __ Push(r0, r1, r2, r3); + + __ ldr(r4, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ ldr(r5, FieldMemOperand(r4, FixedArray::kLengthOffset)); + // r4: source FixedDoubleArray + // r5: number of elements (smi-tagged) + + // Allocate new FixedArray. + __ mov(r0, Operand(FixedDoubleArray::kHeaderSize)); + __ add(r0, r0, Operand(r5, LSL, 1)); + __ AllocateInNewSpace(r0, r6, r7, r9, &gc_required, NO_ALLOCATION_FLAGS); + // r6: destination FixedArray, not tagged as heap object + __ LoadRoot(r9, Heap::kFixedArrayMapRootIndex); + __ str(r9, MemOperand(r6, HeapObject::kMapOffset)); + // Set destination FixedDoubleArray's length. + __ str(r5, MemOperand(r6, FixedDoubleArray::kLengthOffset)); + + // Prepare for conversion loop. + __ add(r4, r4, Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag + 4)); + __ add(r3, r6, Operand(FixedArray::kHeaderSize - 4)); + __ add(r6, r6, Operand(kHeapObjectTag)); + __ add(r5, r3, Operand(r5, LSL, 1)); + __ LoadRoot(r7, Heap::kTheHoleValueRootIndex); + __ LoadRoot(r9, Heap::kHeapNumberMapRootIndex); + // Using offsetted addresses to fully take advantage of pre/post-indexing + // r3: begin of destination FixedArray element fields, not tagged, -4 + // r4: begin of source FixedDoubleArray element fields, not tagged, +4 + // r5: end of destination FixedArray, not tagged, -4 + // r6: destination FixedArray + // r7: the-hole pointer + // r9: heap number map + __ b(&entry); + + // Call into runtime if GC is required. + __ bind(&gc_required); + __ Pop(r2, r3); + __ Pop(r0, r1); + __ pop(lr); + KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode); + + __ bind(&loop); + __ ldr(lr, MemOperand(r4, 8, PostIndex)); + // lr: current element's upper 32 bit + // r4: address of next element's upper 32 bit + __ cmp(lr, Operand(kHoleNanUpper32)); + __ b(eq, &convert_hole); + + // Non-hole double, copy value into a heap number. + __ AllocateHeapNumber(r0, r1, r2, r9, &gc_required); + __ str(lr, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + __ ldr(lr, MemOperand(r4, 12, NegOffset)); + __ str(lr, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); + __ str(r0, MemOperand(r3, 4, PreIndex)); + __ RecordWrite(r6, + r3, + r0, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ b(&entry); + + // Replace the-hole NaN with the-hole pointer. + __ bind(&convert_hole); + __ str(r7, MemOperand(r3, 4, PreIndex)); + + __ bind(&entry); + __ cmp(r3, r5); + __ b(lt, &loop); + + __ Pop(r2, r3); + __ Pop(r0, r1); + // Update receiver's map. + __ str(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); + __ RecordWriteField(r2, + HeapObject::kMapOffset, + r3, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + // Replace receiver's backing store with newly created and filled FixedArray. + __ str(r6, FieldMemOperand(r2, JSObject::kElementsOffset)); + __ RecordWriteField(r2, + JSObject::kElementsOffset, + r6, + r9, + kLRHasBeenSaved, + kDontSaveFPRegs, + EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ pop(lr); +} + + #undef __ } } // namespace v8::internal diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index e6df29e..bfcdb59 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -3299,8 +3299,8 @@ MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic( __ Jump(code, RelocInfo::CODE_TARGET, eq); } else { Label next_map; - __ b(eq, &next_map); - __ mov(r4, Operand(Handle(transitioned_maps->at(i)))); + __ b(ne, &next_map); + __ mov(r3, Operand(Handle(transitioned_maps->at(i)))); __ Jump(code, RelocInfo::CODE_TARGET, al); __ bind(&next_map); } diff --git a/src/code-stubs.cc b/src/code-stubs.cc index a298bc4..896ffad 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -416,7 +416,6 @@ bool ToBooleanStub::Types::CanBeUndetectable() const { void FastElementsConversionStub::Generate(MacroAssembler* masm) { -#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_X64) if (to_ == FAST_ELEMENTS) { if (from_ == FAST_SMI_ONLY_ELEMENTS) { GenerateSmiOnlyToObject(masm); @@ -434,9 +433,6 @@ void FastElementsConversionStub::Generate(MacroAssembler* masm) { } else { UNREACHABLE(); } -#else - KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_); -#endif // V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 } } } // namespace v8::internal diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index b210f74..9e9b7ce 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -6019,7 +6019,7 @@ void FastElementsConversionStub::GenerateDoubleToObject( // Prepare for conversion loop. __ movq(rsi, BitCast(kHoleNanInt64), RelocInfo::NONE); - __ Move(rdi, masm->isolate()->factory()->the_hole_value()); + __ LoadRoot(rdi, Heap::kTheHoleValueRootIndex); // rsi: the-hole NaN // rdi: pointer to the-hole __ jmp(&entry); diff --git a/test/mjsunit/elements-transition.js b/test/mjsunit/elements-transition.js index ab3c690..0900d26 100644 --- a/test/mjsunit/elements-transition.js +++ b/test/mjsunit/elements-transition.js @@ -41,32 +41,38 @@ if (support_smi_only_arrays) { assertTrue(%HasFastSmiOnlyElements(array_1)); assertTrue(%HasFastSmiOnlyElements(array_2)); for (var i = 0; i < length; i++) { - if (i == length - 8 && test_double) { + if (i == length - 5 && test_double) { + // Trigger conversion to fast double elements at length-5. set(array_1, i, 0.5); set(array_2, i, 0.5); assertTrue(%HasFastDoubleElements(array_1)); assertTrue(%HasFastDoubleElements(array_2)); - } else if (i == length - 5 && test_object) { + } else if (i == length - 3 && test_object) { + // Trigger conversion to fast object elements at length-3. set(array_1, i, 'object'); set(array_2, i, 'object'); assertTrue(%HasFastElements(array_1)); assertTrue(%HasFastElements(array_2)); - } else { + } else if (i != length - 7) { + // Set the element to an integer but leave a hole at length-7. set(array_1, i, 2*i+1); set(array_2, i, 2*i+1); } } for (var i = 0; i < length; i++) { - if (i == length - 8 && test_double) { + if (i == length - 5 && test_double) { assertEquals(0.5, array_1[i]); assertEquals(0.5, array_2[i]); - } else if (i == length - 5 && test_object) { + } else if (i == length - 3 && test_object) { assertEquals('object', array_1[i]); assertEquals('object', array_2[i]); - } else { + } else if (i != length - 7) { assertEquals(2*i+1, array_1[i]); assertEquals(2*i+1, array_2[i]); + } else { + assertEquals(undefined, array_1[i]); + assertEquals(undefined, array_2[i]); } } @@ -74,10 +80,10 @@ if (support_smi_only_arrays) { assertEquals(length, array_2.length); } - test(false, false, function(a,i,v){ a[i] = v; }, 100); - test(true, false, function(a,i,v){ a[i] = v; }, 100); - test(false, true, function(a,i,v){ a[i] = v; }, 100); - test(true, true, function(a,i,v){ a[i] = v; }, 100); + test(false, false, function(a,i,v){ a[i] = v; }, 20); + test(true, false, function(a,i,v){ a[i] = v; }, 20); + test(false, true, function(a,i,v){ a[i] = v; }, 20); + test(true, true, function(a,i,v){ a[i] = v; }, 10); test(false, false, function(a,i,v){ a[i] = v; }, 10000); test(true, false, function(a,i,v){ a[i] = v; }, 10000); -- 2.7.4