From: yangguo@chromium.org Date: Fri, 23 Sep 2011 14:19:04 +0000 (+0000) Subject: Porting r9392 to x64 (smi-only arrays). X-Git-Tag: upstream/4.7.83~18374 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=65b1ea22fe37afbd9384f5ea5950107445ad2b70;p=platform%2Fupstream%2Fv8.git Porting r9392 to x64 (smi-only arrays). Review URL: http://codereview.chromium.org/7992003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9416 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index b4eff5a..addf9e1 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -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, diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 2f85e2f..1d9b8ff 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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); } diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 359b595..514015a 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -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)); diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index b73e854..d586b0a 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -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, Label* fail, diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index d681192..db82785 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -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) diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 584c549..3819c1d 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -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); diff --git a/test/mjsunit/element-kind.js b/test/mjsunit/element-kind.js index 1949857..0159f5a 100644 --- a/test/mjsunit/element-kind.js +++ b/test/mjsunit/element-kind.js @@ -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));