Chromium Code Reviews| 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 |