OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |