Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/arm/codegen-arm.cc

Issue 552186: ARM: Implement native substring copying. (Closed)
Patch Set: Changed order of tests to bail out earlier on short substrings. Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 3539 matching lines...) Expand 10 before | Expand all | Expand 10 after
3550 } 3550 }
3551 3551
3552 3552
3553 void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) { 3553 void CodeGenerator::GenerateSubString(ZoneList<Expression*>* args) {
3554 ASSERT_EQ(3, args->length()); 3554 ASSERT_EQ(3, args->length());
3555 3555
3556 Load(args->at(0)); 3556 Load(args->at(0));
3557 Load(args->at(1)); 3557 Load(args->at(1));
3558 Load(args->at(2)); 3558 Load(args->at(2));
3559 3559
3560 frame_->CallRuntime(Runtime::kSubString, 3); 3560 SubStringStub stub;
3561 frame_->CallStub(&stub, 3);
3561 frame_->EmitPush(r0); 3562 frame_->EmitPush(r0);
3562 } 3563 }
3563 3564
3564 3565
3565 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) { 3566 void CodeGenerator::GenerateStringCompare(ZoneList<Expression*>* args) {
3566 ASSERT_EQ(2, args->length()); 3567 ASSERT_EQ(2, args->length());
3567 3568
3568 Load(args->at(0)); 3569 Load(args->at(0));
3569 Load(args->at(1)); 3570 Load(args->at(1));
3570 3571
(...skipping 3257 matching lines...) Expand 10 before | Expand all | Expand 10 after
6828 6829
6829 int CompareStub::MinorKey() { 6830 int CompareStub::MinorKey() {
6830 // Encode the three parameters in a unique 16 bit value. 6831 // Encode the three parameters in a unique 16 bit value.
6831 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16)); 6832 ASSERT((static_cast<unsigned>(cc_) >> 26) < (1 << 16));
6832 int nnn_value = (never_nan_nan_ ? 2 : 0); 6833 int nnn_value = (never_nan_nan_ ? 2 : 0);
6833 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. 6834 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs.
6834 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); 6835 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0);
6835 } 6836 }
6836 6837
6837 6838
6839 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm,
6840 Register dest,
6841 Register src,
6842 Register count,
6843 Register scratch,
6844 bool ascii) {
6845 Label loop;
6846 Label done;
6847 // This loop just copies one character at a time, as it is only used for very
6848 // short strings.
6849 if (!ascii) {
6850 __ add(count, count, Operand(count), SetCC);
6851 } else {
6852 __ cmp(count, Operand(0));
6853 }
6854 __ b(eq, &done);
6855
6856 __ bind(&loop);
6857 __ sub(count, count, Operand(1), SetCC);
6858 __ ldrb(scratch, MemOperand(src, count), pl);
Søren Thygesen Gjesse 2010/02/03 14:25:36 Maybe add a comment on why ldrb is before b. Maybe
Lasse Reichstein 2011/06/14 11:13:06 Done.
6859 __ b(mi, &done);
6860 __ strb(scratch, MemOperand(dest, count));
6861 __ b(&loop);
6862 __ bind(&done);
6863 }
6864
6865
6866 enum CopyCharactersFlags {
6867 COPY_ASCII = 1,
6868 DEST_ALWAYS_ALIGNED = 2
6869 };
6870
Søren Thygesen Gjesse 2010/02/03 14:25:36 Add an empty line.
Lasse Reichstein 2011/06/14 11:13:06 Done.
6871 void StringStubBase::GenerateCopyCharactersLong(MacroAssembler* masm,
6872 Register dest,
6873 Register src,
6874 Register count,
6875 Register scratch1,
6876 Register scratch2,
6877 Register scratch3,
6878 Register scratch4,
6879 Register scratch5,
6880 int flags) {
6881 bool ascii = (flags & COPY_ASCII) != 0;
6882 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0;
Søren Thygesen Gjesse 2010/02/03 14:25:36 Perhaps generated code assert that dest is actuall
Lasse Reichstein 2011/06/14 11:13:06 Added.
6883
6884 // Check that reading an entire aligned word containing the last character
Søren Thygesen Gjesse 2010/02/03 14:25:36 Check -> Ensure.
6885 // of a string will not read outside the allocated area (because we pad up
6886 // to kObjectAlignment).
6887 ASSERT(kObjectAlignment >= 4);
6888 // Assumes word reads and writes are little endian.
6889 // Nothing to do for zero characters.
6890 Label done;
6891 if (!ascii) {
6892 __ add(count, count, Operand(count), SetCC);
6893 } else {
6894 __ cmp(count, Operand(0));
6895 }
6896 __ b(eq, &done);
6897
6898 // Assume that you cannot read (or write) unaligned.
6899 Label byte_loop;
6900 // Must copy at least eight bytes, otherwise just do it one byte at a time.
6901 __ cmp(count, Operand(8));
6902 __ add(count, dest, Operand(count));
6903 Register limit = count; // Read until src equals this.
6904 __ b(lt, &byte_loop);
6905
6906 if (!dest_always_aligned) {
6907 // Align dest by byte copying. Copies between zero and three bytes.
6908 __ and_(scratch4, dest, Operand(0x03), SetCC);
Søren Thygesen Gjesse 2010/02/03 14:25:36 0x03 -> kPointerAlignmentMask?
Lasse Reichstein 2011/06/14 11:13:06 More like "kReadAlignmentMask" (which is word alig
6909 Label dest_aligned;
6910 __ b(eq, &dest_aligned);
6911 __ cmp(scratch4, Operand(2));
6912 __ ldrb(scratch1, MemOperand(src, 1, PostIndex));
6913 __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le);
6914 __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt);
6915 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
6916 __ strb(scratch2, MemOperand(dest, 1, PostIndex), le);
6917 __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt);
6918 __ bind(&dest_aligned);
6919 }
6920
6921 Label simple_loop;
6922
6923 __ sub(scratch4, dest, Operand(src));
6924 __ and_(scratch4, scratch4, Operand(0x03), SetCC);
Søren Thygesen Gjesse 2010/02/03 14:25:36 0x03 -> kPointerAlignmentMask?
6925 __ b(eq, &simple_loop);
6926 // Shift register is number of bits in a source word that
6927 // must be combined with bits in the next source word in order
6928 // to create a destination word.
6929
6930 // Complex loop for src/dst that are not aligned the same way.
6931 {
6932 Label loop;
6933 __ mov(scratch4, Operand(scratch4, LSL, 3));
6934 Register left_shift = scratch4;
6935 __ and_(src, src, Operand(~3)); // Round down to load previous word.
6936 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
6937 // Store the "shift" most significant bits of scratch in the least
6938 // signficant bits (i.e., shift down by (32-shift)).
6939 __ rsb(scratch2, left_shift, Operand(32));
6940 Register right_shift = scratch2;
6941 __ mov(scratch1, Operand(scratch1, LSR, right_shift));
6942
6943 __ bind(&loop);
6944 __ ldr(scratch3, MemOperand(src, 4, PostIndex));
6945 __ sub(scratch5, limit, Operand(dest));
6946 __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift));
6947 __ str(scratch1, MemOperand(dest, 4, PostIndex));
6948 __ mov(scratch1, Operand(scratch3, LSR, right_shift));
6949 // Loop if four or more bytes left to copy.
6950 // Compare to eight, because we did the subtract before increasing dst.
6951 __ sub(scratch5, scratch5, Operand(8), SetCC);
6952 __ b(ge, &loop);
6953 }
6954 // There is now between zero and three bytes left to copy (negative that
6955 // number is in scratch5), and between one and three bytes already read into
6956 // scratch (eight times that number in scratch4). We may have read past
Søren Thygesen Gjesse 2010/02/03 14:25:36 scratch -> scratch1
6957 // the end of the string, but because objects are aligned, we have not read
6958 // past the end of the object.
6959 // Find the minimum of remaining characters to move and preloaded characters
6960 // and write those as bytes.
6961 __ add(scratch5, scratch5, Operand(4), SetCC);
6962 __ b(eq, &done);
6963 __ cmp(scratch4, Operand(scratch5, LSL, 3), ne);
6964 // Move minimum of bytes read and bytes left to copy to scratch4.
6965 __ mov(scratch5, Operand(scratch4, LSR, 3), LeaveCC, lt);
6966 // Between one and three (value in scratch5) characters already read into
6967 // scratch ready to write.
6968 __ cmp(scratch5, Operand(2));
6969 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
6970 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge);
6971 __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge);
6972 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt);
6973 __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt);
6974 // Copy any remaining bytes.
6975 __ b(&byte_loop);
6976
6977 // Simple loop.
6978 // Copy words from src to dst. Both are word aligned.
6979 __ bind(&simple_loop);
6980 {
6981 Label loop;
6982 __ bind(&loop);
6983 __ ldr(scratch1, MemOperand(src, 4, PostIndex));
6984 __ sub(scratch3, limit, Operand(dest));
6985 __ str(scratch1, MemOperand(dest, 4, PostIndex));
6986 __ cmp(scratch3, Operand(8));
Søren Thygesen Gjesse 2010/02/03 14:25:36 I guess that this need to be 8 and not 4.
Lasse Reichstein 2011/06/14 11:13:06 Added comment to explain.
6987 __ b(ge, &loop);
6988 }
6989
6990 // Copy bytes from src to dst until dst hits limit.
6991 __ bind(&byte_loop);
6992 __ cmp(dest, Operand(limit));
6993 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt);
6994 __ b(ge, &done);
6995 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
6996 __ b(&byte_loop);
6997
6998 __ bind(&done);
6999 }
7000
7001
7002 void SubStringStub::Generate(MacroAssembler* masm) {
7003 Label runtime;
7004
7005 // Stack frame on entry.
7006 // lr: return address
7007 // sp[0]: to
7008 // sp[4]: from
7009 // sp[8]: string
7010
7011 // This stub is called from the native-call %_SubString(...), so
7012 // nothing can be assumed about the arguments. It is tested that:
7013 // "string" is a sequential string,
7014 // both "from" and "to" are smis, and
7015 // 0 <= from <= to <= string.length.
7016 // If any of these assumptions fail, we call the runtime system.
7017
7018 static const int kToOffset = 0 * kPointerSize;
7019 static const int kFromOffset = 1 * kPointerSize;
7020 static const int kStringOffset = 2 * kPointerSize;
7021
7022
7023 // Check bounds and smi-ness.
7024 __ ldr(r7, MemOperand(sp, kToOffset));
7025 __ ldr(r6, MemOperand(sp, kFromOffset));
7026 ASSERT_EQ(0, kSmiTag);
7027 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
7028 // I.e., arithmetic shift right by one un-smi-tags.
7029 __ mov(r2, Operand(r7, ASR, 1), SetCC);
7030 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc);
7031 // If either r2 or r6 had the smi tag bit set, then carry is set now.
7032 __ b(cs, &runtime); // Either "from" or "to" is not a smi.
7033 __ b(mi, &runtime); // From is negative.
7034
7035 __ sub(r2, r2, Operand(r3), SetCC);
7036 __ b(mi, &runtime); // Fail if from > to.
7037 // Handle sub-strings of length 2 and less in the runtime system.
7038 __ cmp(r2, Operand(2));
7039 __ b(le, &runtime);
7040
7041 // r2: length
7042 // r6: from (smi)
7043 // r7: to (smi)
7044
7045 // Make sure first argument is a sequential (or flat) string.
7046 __ ldr(r5, MemOperand(sp, kStringOffset));
7047 ASSERT_EQ(0, kSmiTag);
7048 __ tst(r5, Operand(kSmiTagMask));
7049 __ b(eq, &runtime);
7050 Condition is_string = masm->IsObjectStringType(r5, r1);
7051 __ b(NegateCondition(is_string), &runtime);
7052
7053 // r1: instance type
7054 // r2: length
7055 // r5: string
7056 // r6: from (smi)
7057 // r7: to (smi)
7058 Label seq_string;
7059 __ and_(r4, r1, Operand(kStringRepresentationMask));
7060 ASSERT(kSeqStringTag < kConsStringTag);
7061 ASSERT(kExternalStringTag > kConsStringTag);
7062 __ cmp(r4, Operand(kConsStringTag));
7063 __ b(gt, &runtime); // External strings go to runtime.
7064 __ b(lt, &seq_string); // Sequential strings are handled directly.
7065
7066 // Cons string. Try to recurse (once) on the first substring.
7067 // (This adds a little more generality than necessary to handle flattened
7068 // cons strings, but not much).
7069 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset));
7070 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
7071 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset));
7072 __ tst(r1, Operand(kStringRepresentationMask));
7073 ASSERT_EQ(0, kSeqStringTag);
7074 __ b(ne, &runtime); // Cons and External strings go to runtime.
7075
7076 // Definitly a sequential string.
7077 __ bind(&seq_string);
7078
7079 // r1: instance type.
7080 // r2: length
7081 // r5: string
7082 // r6: from (smi)
7083 // r7: to (smi)
7084 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset));
7085 __ cmp(r4, Operand(r7, ASR, 1));
7086 __ b(lt, &runtime); // Fail if to > length.
7087
7088 // r1: instance type.
7089 // r2: result string length.
7090 // r5: string.
7091 // r6: from offset (smi)
7092 // Check for flat ascii string.
7093 Label non_ascii_flat;
7094 __ tst(r1, Operand(kStringEncodingMask));
7095 ASSERT_EQ(0, kTwoByteStringTag);
7096 __ b(eq, &non_ascii_flat);
7097
7098 // Allocate the result.
7099 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
7100
7101 // r0: result string.
7102 // r2: result string length.
7103 // r5: string.
7104 // r6: from offset (smi)
7105 // Locate first character of result.
7106 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
Søren Thygesen Gjesse 2010/02/03 14:25:36 // Locate first character of "from".
Lasse Reichstein 2011/06/14 11:13:06 Comment added.
7107 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
7108 __ add(r5, r5, Operand(r6, ASR, 1));
7109
7110 // r0: result string.
7111 // r1: first character of result string.
7112 // r2: result string length.
7113 // r5: first character of sub string to copy.
7114 ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask);
7115 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
7116 COPY_ASCII | DEST_ALWAYS_ALIGNED);
7117 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
7118 __ add(sp, sp, Operand(3 * kPointerSize));
7119 __ Ret();
7120
7121 __ bind(&non_ascii_flat);
7122 // r2: result string length.
7123 // r5: string.
7124 // r6: from offset (smi)
7125 // Check for flat two byte string.
7126
7127 // Allocate the result.
7128 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
7129
7130 // r0: result string.
7131 // r2: result string length.
7132 // r5: string.
7133 // Locate first character of result.
7134 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
Søren Thygesen Gjesse 2010/02/03 14:25:36 // Locate first character of "from".
7135 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
7136 // As "from" is a smi it is 2 times the value which matches the size of a two
7137 // byte character.
7138 __ add(r5, r5, Operand(r6));
7139
7140 // r0: result string.
7141 // r1: first character of result.
7142 // r2: result length.
7143 // r5: first character of string to copy.
7144 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask);
7145 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
7146 DEST_ALWAYS_ALIGNED);
7147 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4);
7148 __ add(sp, sp, Operand(3 * kPointerSize));
7149 __ Ret();
7150
7151 // Just jump to runtime to create the sub string.
7152 __ bind(&runtime);
7153 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1);
7154 }
6838 7155
6839 7156
6840 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 7157 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
6841 Register left, 7158 Register left,
6842 Register right, 7159 Register right,
6843 Register scratch1, 7160 Register scratch1,
6844 Register scratch2, 7161 Register scratch2,
6845 Register scratch3, 7162 Register scratch3,
6846 Register scratch4) { 7163 Register scratch4) {
6847 Label compare_lengths; 7164 Label compare_lengths;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
6926 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 7243 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
6927 // tagged as a small integer. 7244 // tagged as a small integer.
6928 __ bind(&runtime); 7245 __ bind(&runtime);
6929 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); 7246 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
6930 } 7247 }
6931 7248
6932 7249
6933 #undef __ 7250 #undef __
6934 7251
6935 } } // namespace v8::internal 7252 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/macro-assembler-arm.h » ('j') | test/mjsunit/substr.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698