From 198e33560b8cd20483e4ffa93a2571b44f425c5e Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Thu, 24 Nov 2011 10:16:39 +0000 Subject: [PATCH] Porting r10023 and r10054 to x64 (pointer cache for external strings). Review URL: http://codereview.chromium.org/8662009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10058 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/codegen.h | 17 ------ src/ia32/codegen-ia32.cc | 10 ++-- src/ia32/codegen-ia32.h | 16 ++++++ src/x64/code-stubs-x64.cc | 64 +-------------------- src/x64/codegen-x64.cc | 102 +++++++++++++++++++++++++++++++++ src/x64/codegen-x64.h | 15 +++++ src/x64/lithium-codegen-x64.cc | 80 ++------------------------ 7 files changed, 145 insertions(+), 159 deletions(-) diff --git a/src/codegen.h b/src/codegen.h index e6d5399b5c..5360d3ef3c 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -94,23 +94,6 @@ class ElementsTransitionGenerator : public AllStatic { DISALLOW_COPY_AND_ASSIGN(ElementsTransitionGenerator); }; - -class StringCharLoadGenerator : public AllStatic { - public: - // Generates the code for handling different string types and loading the - // indexed character into |result|. We expect |index| as untagged input and - // |result| as untagged output. - static void Generate(MacroAssembler* masm, - Factory* factory, - Register string, - Register index, - Register result, - Label* call_runtime); - - private: - DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); -}; - } } // namespace v8::internal #endif // V8_CODEGEN_H_ diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index e195de1f1c..75e4ce148e 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -579,7 +579,7 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ movzx_b(result, Operand(result, index, times_1, 0)); __ jmp(&done); - // Handle conses. + // Handle cons strings. // Check whether the right hand side is the empty string (i.e. if // this is really a flat string in a cons string). If that is not // the case we would rather go to the runtime system now to flatten @@ -594,11 +594,9 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm, __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); - // Check whether the string is sequential. The only non-sequential - // shapes we support have just been unwrapped above. - // Note that if the original string is a cons or slice with an external - // string as underlying string, we pass that unpacked underlying string with - // the adjusted index to the runtime function. + // Distinguish sequential and external strings. Only these two string + // representations can reach here (slices and flat cons strings have been + // reduced to the underlying sequential or external string). __ bind(&check_sequential); STATIC_ASSERT(kSeqStringTag == 0); __ test(result, Immediate(kStringRepresentationMask)); diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index c85fa83e9e..f4ab0b50f6 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -72,6 +72,22 @@ class CodeGenerator { }; +class StringCharLoadGenerator : public AllStatic { + public: + // Generates the code for handling different string types and loading the + // indexed character into |result|. We expect |index| as untagged input and + // |result| as untagged output. + static void Generate(MacroAssembler* masm, + Factory* factory, + Register string, + Register index, + Register result, + Label* call_runtime); + + private: + DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); +}; + } } // namespace v8::internal #endif // V8_IA32_CODEGEN_IA32_H_ diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index b8f820d7f5..19326f2775 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -4157,70 +4157,11 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { __ SmiCompare(index_, FieldOperand(object_, String::kLengthOffset)); __ j(above_equal, index_out_of_range_); - // We need special handling for non-flat strings. - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(result_, Immediate(kStringRepresentationMask)); - __ j(zero, &flat_string); - - // Handle non-flat strings. - __ and_(result_, Immediate(kStringRepresentationMask)); - STATIC_ASSERT(kConsStringTag < kExternalStringTag); - STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); - __ cmpb(result_, Immediate(kExternalStringTag)); - __ j(greater, &sliced_string); - __ j(equal, &call_runtime_); - - // ConsString. - // Check whether the right hand side is the empty string (i.e. if - // this is really a flat string in a cons string). If that is not - // the case we would rather go to the runtime system now to flatten - // the string. - Label assure_seq_string; - __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset), - Heap::kEmptyStringRootIndex); - __ j(not_equal, &call_runtime_); - // Get the first of the two parts. - __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset)); - __ jmp(&assure_seq_string, Label::kNear); - - // SlicedString, unpack and add offset. - __ bind(&sliced_string); - __ addq(index_, FieldOperand(object_, SlicedString::kOffsetOffset)); - __ movq(object_, FieldOperand(object_, SlicedString::kParentOffset)); - - // Assure that we are dealing with a sequential string. Go to runtime if not. - // Note that if the original string is a cons or slice with an external - // string as underlying string, we pass that unpacked underlying string with - // the adjusted index to the runtime function. - __ bind(&assure_seq_string); - __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); - __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(result_, Immediate(kStringRepresentationMask)); - __ j(not_zero, &call_runtime_); - - // Check for 1-byte or 2-byte string. - __ bind(&flat_string); - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); __ SmiToInteger32(index_, index_); - __ testb(result_, Immediate(kStringEncodingMask)); - __ j(not_zero, &ascii_string); - // 2-byte string. - // Load the 2-byte character code into the result register. - __ movzxwl(result_, FieldOperand(object_, - index_, times_2, - SeqTwoByteString::kHeaderSize)); - __ jmp(&got_char_code); + StringCharLoadGenerator::Generate( + masm, object_, index_, result_, &call_runtime_); - // ASCII string. - // Load the byte into the result register. - __ bind(&ascii_string); - __ movzxbl(result_, FieldOperand(object_, - index_, times_1, - SeqAsciiString::kHeaderSize)); - __ bind(&got_char_code); __ Integer32ToSmi(result_, result_); __ bind(&exit_); } @@ -4270,6 +4211,7 @@ void StringCharCodeAtGenerator::GenerateSlow( __ bind(&call_runtime_); call_helper.BeforeCall(masm); __ push(object_); + __ Integer32ToSmi(index_, index_); __ push(index_); __ CallRuntime(Runtime::kStringCharCodeAt, 2); if (!result_.is(rax)) { diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 4090ce40c4..094bbe7204 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -367,6 +367,108 @@ void ElementsTransitionGenerator::GenerateDoubleToObject( __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); } + +void StringCharLoadGenerator::Generate(MacroAssembler* masm, + Register string, + Register index, + Register result, + Label* call_runtime) { + // Fetch the instance type of the receiver into result register. + __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); + __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); + + // We need special handling for indirect strings. + Label check_sequential; + __ testb(result, Immediate(kIsIndirectStringMask)); + __ j(zero, &check_sequential); + + // Dispatch on the indirect string shape: slice or cons. + Label cons_string; + __ testb(result, Immediate(kSlicedNotConsMask)); + __ j(zero, &cons_string, Label::kNear); + + // Handle slices. + Label indirect_string_loaded; + __ SmiToInteger32(result, FieldOperand(string, SlicedString::kOffsetOffset)); + __ addq(index, result); + __ movq(string, FieldOperand(string, SlicedString::kParentOffset)); + __ jmp(&indirect_string_loaded, Label::kNear); + + // Handle external strings. + Label external_string, ascii_external, done; + __ bind(&external_string); + if (FLAG_debug_code) { + // Assert that we do not have a cons or slice (indirect strings) here. + // Sequential strings have already been ruled out. + __ testb(result, Immediate(kIsIndirectStringMask)); + __ Assert(zero, "external string expected, but not found"); + } + // Rule out short external strings. + STATIC_CHECK(kShortExternalStringTag != 0); + __ testb(result, Immediate(kShortExternalStringTag)); + __ j(not_zero, call_runtime); + // Check encoding. + STATIC_ASSERT(kTwoByteStringTag == 0); + __ testb(result, Immediate(kStringEncodingMask)); + __ movq(result, FieldOperand(string, ExternalString::kResourceDataOffset)); + __ j(not_equal, &ascii_external, Label::kNear); + // Two-byte string. + __ movzxwl(result, Operand(result, index, times_2, 0)); + __ jmp(&done); + __ bind(&ascii_external); + // Ascii string. + __ movzxbl(result, Operand(result, index, times_1, 0)); + __ jmp(&done); + + // Handle cons strings. + // Check whether the right hand side is the empty string (i.e. if + // this is really a flat string in a cons string). If that is not + // the case we would rather go to the runtime system now to flatten + // the string. + __ bind(&cons_string); + __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset), + Heap::kEmptyStringRootIndex); + __ j(not_equal, call_runtime); + __ movq(string, FieldOperand(string, ConsString::kFirstOffset)); + + __ bind(&indirect_string_loaded); + __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); + __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); + + // Distinguish sequential and external strings. Only these two string + // representations can reach here (slices and flat cons strings have been + // reduced to the underlying sequential or external string). + __ bind(&check_sequential); + STATIC_ASSERT(kSeqStringTag == 0); + __ testb(result, Immediate(kStringRepresentationMask)); + __ j(not_zero, &external_string); + + // Dispatch on the encoding: ASCII or two-byte. + Label ascii_string; + STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + __ testb(result, Immediate(kStringEncodingMask)); + __ j(not_zero, &ascii_string, Label::kNear); + + // Two-byte string. + // Load the two-byte character code into the result register. + STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); + __ movzxwl(result, FieldOperand(string, + index, + times_2, + SeqTwoByteString::kHeaderSize)); + __ jmp(&done, Label::kNear); + + // ASCII string. + // Load the byte into the result register. + __ bind(&ascii_string); + __ movzxbl(result, FieldOperand(string, + index, + times_1, + SeqAsciiString::kHeaderSize)); + __ bind(&done); +} + #undef __ } } // namespace v8::internal diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h index a0648cec64..2e80751033 100644 --- a/src/x64/codegen-x64.h +++ b/src/x64/codegen-x64.h @@ -69,6 +69,21 @@ class CodeGenerator: public AstVisitor { }; +class StringCharLoadGenerator : public AllStatic { + public: + // Generates the code for handling different string types and loading the + // indexed character into |result|. We expect |index| as untagged input and + // |result| as untagged output. + static void Generate(MacroAssembler* masm, + Register string, + Register index, + Register result, + Label* call_runtime); + + private: + DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator); +}; + } } // namespace v8::internal #endif // V8_X64_CODEGEN_X64_H_ diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 27ed3b5df9..0668c2efdd 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3306,84 +3306,14 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { LStringCharCodeAt* instr_; }; - Register string = ToRegister(instr->string()); - Register index = ToRegister(instr->index()); - Register result = ToRegister(instr->result()); - DeferredStringCharCodeAt* deferred = new DeferredStringCharCodeAt(this, instr); - // Fetch the instance type of the receiver into result register. - __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); - __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); - - // We need special handling for indirect strings. - Label check_sequential; - __ testb(result, Immediate(kIsIndirectStringMask)); - __ j(zero, &check_sequential, Label::kNear); - - // Dispatch on the indirect string shape: slice or cons. - Label cons_string; - __ testb(result, Immediate(kSlicedNotConsMask)); - __ j(zero, &cons_string, Label::kNear); - - // Handle slices. - Label indirect_string_loaded; - __ SmiToInteger32(result, FieldOperand(string, SlicedString::kOffsetOffset)); - __ addq(index, result); - __ movq(string, FieldOperand(string, SlicedString::kParentOffset)); - __ jmp(&indirect_string_loaded, Label::kNear); - - // Handle conses. - // Check whether the right hand side is the empty string (i.e. if - // this is really a flat string in a cons string). If that is not - // the case we would rather go to the runtime system now to flatten - // the string. - __ bind(&cons_string); - __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset), - Heap::kEmptyStringRootIndex); - __ j(not_equal, deferred->entry()); - __ movq(string, FieldOperand(string, ConsString::kFirstOffset)); - - __ bind(&indirect_string_loaded); - __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); - __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); - - // Check whether the string is sequential. The only non-sequential - // shapes we support have just been unwrapped above. - // Note that if the original string is a cons or slice with an external - // string as underlying string, we pass that unpacked underlying string with - // the adjusted index to the runtime function. - __ bind(&check_sequential); - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(result, Immediate(kStringRepresentationMask)); - __ j(not_zero, deferred->entry()); - - // Dispatch on the encoding: ASCII or two-byte. - Label ascii_string; - STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ testb(result, Immediate(kStringEncodingMask)); - __ j(not_zero, &ascii_string, Label::kNear); - - // Two-byte string. - // Load the two-byte character code into the result register. - Label done; - STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); - __ movzxwl(result, FieldOperand(string, - index, - times_2, - SeqTwoByteString::kHeaderSize)); - __ jmp(&done, Label::kNear); - - // ASCII string. - // Load the byte into the result register. - __ bind(&ascii_string); - __ movzxbl(result, FieldOperand(string, - index, - times_1, - SeqAsciiString::kHeaderSize)); - __ bind(&done); + StringCharLoadGenerator::Generate(masm(), + ToRegister(instr->string()), + ToRegister(instr->index()), + ToRegister(instr->result()), + deferred->entry()); __ bind(deferred->exit()); }