| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/intrinsifier.h" | 8 #include "vm/intrinsifier.h" |
| 9 | 9 |
| 10 #include "vm/assembler.h" | 10 #include "vm/assembler.h" |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 __ b(&fall_through, NE); \ | 190 __ b(&fall_through, NE); \ |
| 191 __ CompareRegisters(R2, ZR); \ | 191 __ CompareRegisters(R2, ZR); \ |
| 192 __ b(&fall_through, LT); \ | 192 __ b(&fall_through, LT); \ |
| 193 __ SmiUntag(R2); \ | 193 __ SmiUntag(R2); \ |
| 194 /* Check for maximum allowed length. */ \ | 194 /* Check for maximum allowed length. */ \ |
| 195 /* R2: untagged array length. */ \ | 195 /* R2: untagged array length. */ \ |
| 196 __ CompareImmediate(R2, max_len); \ | 196 __ CompareImmediate(R2, max_len); \ |
| 197 __ b(&fall_through, GT); \ | 197 __ b(&fall_through, GT); \ |
| 198 __ LslImmediate(R2, R2, scale_shift); \ | 198 __ LslImmediate(R2, R2, scale_shift); \ |
| 199 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ | 199 const intptr_t fixed_size = sizeof(Raw##type_name) + kObjectAlignment - 1; \ |
| 200 __ AddImmediate(R2, R2, fixed_size); \ | 200 __ AddImmediate(R2, fixed_size); \ |
| 201 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \ | 201 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \ |
| 202 Heap::Space space = Heap::kNew; \ | 202 Heap::Space space = Heap::kNew; \ |
| 203 __ ldr(R3, Address(THR, Thread::heap_offset())); \ | 203 __ ldr(R3, Address(THR, Thread::heap_offset())); \ |
| 204 __ ldr(R0, Address(R3, Heap::TopOffset(space))); \ | 204 __ ldr(R0, Address(R3, Heap::TopOffset(space))); \ |
| 205 \ | 205 \ |
| 206 /* R2: allocation size. */ \ | 206 /* R2: allocation size. */ \ |
| 207 __ adds(R1, R0, Operand(R2)); \ | 207 __ adds(R1, R0, Operand(R2)); \ |
| 208 __ b(&fall_through, CS); /* Fail on unsigned overflow. */ \ | 208 __ b(&fall_through, CS); /* Fail on unsigned overflow. */ \ |
| 209 \ | 209 \ |
| 210 /* Check if the allocation fits into the remaining space. */ \ | 210 /* Check if the allocation fits into the remaining space. */ \ |
| 211 /* R0: potential new object start. */ \ | 211 /* R0: potential new object start. */ \ |
| 212 /* R1: potential next object start. */ \ | 212 /* R1: potential next object start. */ \ |
| 213 /* R2: allocation size. */ \ | 213 /* R2: allocation size. */ \ |
| 214 /* R3: heap. */ \ | 214 /* R3: heap. */ \ |
| 215 __ ldr(R6, Address(R3, Heap::EndOffset(space))); \ | 215 __ ldr(R6, Address(R3, Heap::EndOffset(space))); \ |
| 216 __ cmp(R1, Operand(R6)); \ | 216 __ cmp(R1, Operand(R6)); \ |
| 217 __ b(&fall_through, CS); \ | 217 __ b(&fall_through, CS); \ |
| 218 \ | 218 \ |
| 219 /* Successfully allocated the object(s), now update top to point to */ \ | 219 /* Successfully allocated the object(s), now update top to point to */ \ |
| 220 /* next object start and initialize the object. */ \ | 220 /* next object start and initialize the object. */ \ |
| 221 __ str(R1, Address(R3, Heap::TopOffset(space))); \ | 221 __ str(R1, Address(R3, Heap::TopOffset(space))); \ |
| 222 __ AddImmediate(R0, R0, kHeapObjectTag); \ | 222 __ AddImmediate(R0, kHeapObjectTag); \ |
| 223 NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2, space)); \ | 223 NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2, space)); \ |
| 224 /* Initialize the tags. */ \ | 224 /* Initialize the tags. */ \ |
| 225 /* R0: new object start as a tagged pointer. */ \ | 225 /* R0: new object start as a tagged pointer. */ \ |
| 226 /* R1: new object end address. */ \ | 226 /* R1: new object end address. */ \ |
| 227 /* R2: allocation size. */ \ | 227 /* R2: allocation size. */ \ |
| 228 { \ | 228 { \ |
| 229 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); \ | 229 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); \ |
| 230 __ LslImmediate(R2, R2, RawObject::kSizeTagPos - kObjectAlignmentLog2); \ | 230 __ LslImmediate(R2, R2, RawObject::kSizeTagPos - kObjectAlignmentLog2); \ |
| 231 __ csel(R2, ZR, R2, HI); \ | 231 __ csel(R2, ZR, R2, HI); \ |
| 232 \ | 232 \ |
| (...skipping 1616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1849 // if (start < 0) return false; | 1849 // if (start < 0) return false; |
| 1850 __ cmp(R1, Operand(0)); | 1850 __ cmp(R1, Operand(0)); |
| 1851 __ b(return_false, LT); | 1851 __ b(return_false, LT); |
| 1852 | 1852 |
| 1853 // if (start + other.length > this.length) return false; | 1853 // if (start + other.length > this.length) return false; |
| 1854 __ add(R3, R1, Operand(R9)); | 1854 __ add(R3, R1, Operand(R9)); |
| 1855 __ cmp(R3, Operand(R8)); | 1855 __ cmp(R3, Operand(R8)); |
| 1856 __ b(return_false, GT); | 1856 __ b(return_false, GT); |
| 1857 | 1857 |
| 1858 if (receiver_cid == kOneByteStringCid) { | 1858 if (receiver_cid == kOneByteStringCid) { |
| 1859 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag); | 1859 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1860 __ add(R0, R0, Operand(R1)); | 1860 __ add(R0, R0, Operand(R1)); |
| 1861 } else { | 1861 } else { |
| 1862 ASSERT(receiver_cid == kTwoByteStringCid); | 1862 ASSERT(receiver_cid == kTwoByteStringCid); |
| 1863 __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag); | 1863 __ AddImmediate(R0, TwoByteString::data_offset() - kHeapObjectTag); |
| 1864 __ add(R0, R0, Operand(R1)); | 1864 __ add(R0, R0, Operand(R1)); |
| 1865 __ add(R0, R0, Operand(R1)); | 1865 __ add(R0, R0, Operand(R1)); |
| 1866 } | 1866 } |
| 1867 if (other_cid == kOneByteStringCid) { | 1867 if (other_cid == kOneByteStringCid) { |
| 1868 __ AddImmediate(R2, R2, OneByteString::data_offset() - kHeapObjectTag); | 1868 __ AddImmediate(R2, OneByteString::data_offset() - kHeapObjectTag); |
| 1869 } else { | 1869 } else { |
| 1870 ASSERT(other_cid == kTwoByteStringCid); | 1870 ASSERT(other_cid == kTwoByteStringCid); |
| 1871 __ AddImmediate(R2, R2, TwoByteString::data_offset() - kHeapObjectTag); | 1871 __ AddImmediate(R2, TwoByteString::data_offset() - kHeapObjectTag); |
| 1872 } | 1872 } |
| 1873 | 1873 |
| 1874 // i = 0 | 1874 // i = 0 |
| 1875 __ LoadImmediate(R3, 0); | 1875 __ LoadImmediate(R3, 0); |
| 1876 | 1876 |
| 1877 // do | 1877 // do |
| 1878 Label loop; | 1878 Label loop; |
| 1879 __ Bind(&loop); | 1879 __ Bind(&loop); |
| 1880 | 1880 |
| 1881 // this.codeUnitAt(i + start) | 1881 // this.codeUnitAt(i + start) |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1948 __ tsti(R1, Immediate(kSmiTagMask)); | 1948 __ tsti(R1, Immediate(kSmiTagMask)); |
| 1949 __ b(&fall_through, NE); // Index is not a Smi. | 1949 __ b(&fall_through, NE); // Index is not a Smi. |
| 1950 // Range check. | 1950 // Range check. |
| 1951 __ ldr(R2, FieldAddress(R0, String::length_offset())); | 1951 __ ldr(R2, FieldAddress(R0, String::length_offset())); |
| 1952 __ cmp(R1, Operand(R2)); | 1952 __ cmp(R1, Operand(R2)); |
| 1953 __ b(&fall_through, CS); // Runtime throws exception. | 1953 __ b(&fall_through, CS); // Runtime throws exception. |
| 1954 | 1954 |
| 1955 __ CompareClassId(R0, kOneByteStringCid); | 1955 __ CompareClassId(R0, kOneByteStringCid); |
| 1956 __ b(&try_two_byte_string, NE); | 1956 __ b(&try_two_byte_string, NE); |
| 1957 __ SmiUntag(R1); | 1957 __ SmiUntag(R1); |
| 1958 __ AddImmediate(R0, R0, OneByteString::data_offset() - kHeapObjectTag); | 1958 __ AddImmediate(R0, OneByteString::data_offset() - kHeapObjectTag); |
| 1959 __ ldr(R1, Address(R0, R1), kUnsignedByte); | 1959 __ ldr(R1, Address(R0, R1), kUnsignedByte); |
| 1960 __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols); | 1960 __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols); |
| 1961 __ b(&fall_through, GE); | 1961 __ b(&fall_through, GE); |
| 1962 __ ldr(R0, Address(THR, Thread::predefined_symbols_address_offset())); | 1962 __ ldr(R0, Address(THR, Thread::predefined_symbols_address_offset())); |
| 1963 __ AddImmediate(R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize); | 1963 __ AddImmediate(R0, Symbols::kNullCharCodeSymbolOffset * kWordSize); |
| 1964 __ ldr(R0, Address(R0, R1, UXTX, Address::Scaled)); | 1964 __ ldr(R0, Address(R0, R1, UXTX, Address::Scaled)); |
| 1965 __ ret(); | 1965 __ ret(); |
| 1966 | 1966 |
| 1967 __ Bind(&try_two_byte_string); | 1967 __ Bind(&try_two_byte_string); |
| 1968 __ CompareClassId(R0, kTwoByteStringCid); | 1968 __ CompareClassId(R0, kTwoByteStringCid); |
| 1969 __ b(&fall_through, NE); | 1969 __ b(&fall_through, NE); |
| 1970 ASSERT(kSmiTagShift == 1); | 1970 ASSERT(kSmiTagShift == 1); |
| 1971 __ AddImmediate(R0, R0, TwoByteString::data_offset() - kHeapObjectTag); | 1971 __ AddImmediate(R0, TwoByteString::data_offset() - kHeapObjectTag); |
| 1972 __ ldr(R1, Address(R0, R1), kUnsignedHalfword); | 1972 __ ldr(R1, Address(R0, R1), kUnsignedHalfword); |
| 1973 __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols); | 1973 __ CompareImmediate(R1, Symbols::kNumberOfOneCharCodeSymbols); |
| 1974 __ b(&fall_through, GE); | 1974 __ b(&fall_through, GE); |
| 1975 __ ldr(R0, Address(THR, Thread::predefined_symbols_address_offset())); | 1975 __ ldr(R0, Address(THR, Thread::predefined_symbols_address_offset())); |
| 1976 __ AddImmediate(R0, R0, Symbols::kNullCharCodeSymbolOffset * kWordSize); | 1976 __ AddImmediate(R0, Symbols::kNullCharCodeSymbolOffset * kWordSize); |
| 1977 __ ldr(R0, Address(R0, R1, UXTX, Address::Scaled)); | 1977 __ ldr(R0, Address(R0, R1, UXTX, Address::Scaled)); |
| 1978 __ ret(); | 1978 __ ret(); |
| 1979 | 1979 |
| 1980 __ Bind(&fall_through); | 1980 __ Bind(&fall_through); |
| 1981 } | 1981 } |
| 1982 | 1982 |
| 1983 | 1983 |
| 1984 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { | 1984 void Intrinsifier::StringBaseIsEmpty(Assembler* assembler) { |
| 1985 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1985 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1986 __ ldr(R0, FieldAddress(R0, String::length_offset())); | 1986 __ ldr(R0, FieldAddress(R0, String::length_offset())); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 static void TryAllocateOnebyteString(Assembler* assembler, | 2059 static void TryAllocateOnebyteString(Assembler* assembler, |
| 2060 Label* ok, | 2060 Label* ok, |
| 2061 Label* failure) { | 2061 Label* failure) { |
| 2062 const Register length_reg = R2; | 2062 const Register length_reg = R2; |
| 2063 Label fail; | 2063 Label fail; |
| 2064 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, R0, failure)); | 2064 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, R0, failure)); |
| 2065 __ mov(R6, length_reg); // Save the length register. | 2065 __ mov(R6, length_reg); // Save the length register. |
| 2066 // TODO(koda): Protect against negative length and overflow here. | 2066 // TODO(koda): Protect against negative length and overflow here. |
| 2067 __ SmiUntag(length_reg); | 2067 __ SmiUntag(length_reg); |
| 2068 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; | 2068 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; |
| 2069 __ AddImmediate(length_reg, length_reg, fixed_size); | 2069 __ AddImmediate(length_reg, fixed_size); |
| 2070 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); | 2070 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); |
| 2071 | 2071 |
| 2072 const intptr_t cid = kOneByteStringCid; | 2072 const intptr_t cid = kOneByteStringCid; |
| 2073 Heap::Space space = Heap::kNew; | 2073 Heap::Space space = Heap::kNew; |
| 2074 __ ldr(R3, Address(THR, Thread::heap_offset())); | 2074 __ ldr(R3, Address(THR, Thread::heap_offset())); |
| 2075 __ ldr(R0, Address(R3, Heap::TopOffset(space))); | 2075 __ ldr(R0, Address(R3, Heap::TopOffset(space))); |
| 2076 | 2076 |
| 2077 // length_reg: allocation size. | 2077 // length_reg: allocation size. |
| 2078 __ adds(R1, R0, Operand(length_reg)); | 2078 __ adds(R1, R0, Operand(length_reg)); |
| 2079 __ b(&fail, CS); // Fail on unsigned overflow. | 2079 __ b(&fail, CS); // Fail on unsigned overflow. |
| 2080 | 2080 |
| 2081 // Check if the allocation fits into the remaining space. | 2081 // Check if the allocation fits into the remaining space. |
| 2082 // R0: potential new object start. | 2082 // R0: potential new object start. |
| 2083 // R1: potential next object start. | 2083 // R1: potential next object start. |
| 2084 // R2: allocation size. | 2084 // R2: allocation size. |
| 2085 // R3: heap. | 2085 // R3: heap. |
| 2086 __ ldr(R7, Address(R3, Heap::EndOffset(space))); | 2086 __ ldr(R7, Address(R3, Heap::EndOffset(space))); |
| 2087 __ cmp(R1, Operand(R7)); | 2087 __ cmp(R1, Operand(R7)); |
| 2088 __ b(&fail, CS); | 2088 __ b(&fail, CS); |
| 2089 | 2089 |
| 2090 // Successfully allocated the object(s), now update top to point to | 2090 // Successfully allocated the object(s), now update top to point to |
| 2091 // next object start and initialize the object. | 2091 // next object start and initialize the object. |
| 2092 __ str(R1, Address(R3, Heap::TopOffset(space))); | 2092 __ str(R1, Address(R3, Heap::TopOffset(space))); |
| 2093 __ AddImmediate(R0, R0, kHeapObjectTag); | 2093 __ AddImmediate(R0, kHeapObjectTag); |
| 2094 NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2, space)); | 2094 NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2, space)); |
| 2095 | 2095 |
| 2096 // Initialize the tags. | 2096 // Initialize the tags. |
| 2097 // R0: new object start as a tagged pointer. | 2097 // R0: new object start as a tagged pointer. |
| 2098 // R1: new object end address. | 2098 // R1: new object end address. |
| 2099 // R2: allocation size. | 2099 // R2: allocation size. |
| 2100 { | 2100 { |
| 2101 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; | 2101 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; |
| 2102 | 2102 |
| 2103 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); | 2103 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2143 __ sub(R2, R2, Operand(TMP)); | 2143 __ sub(R2, R2, Operand(TMP)); |
| 2144 TryAllocateOnebyteString(assembler, &ok, &fall_through); | 2144 TryAllocateOnebyteString(assembler, &ok, &fall_through); |
| 2145 __ Bind(&ok); | 2145 __ Bind(&ok); |
| 2146 // R0: new string as tagged pointer. | 2146 // R0: new string as tagged pointer. |
| 2147 // Copy string. | 2147 // Copy string. |
| 2148 __ ldr(R3, Address(SP, kStringOffset)); | 2148 __ ldr(R3, Address(SP, kStringOffset)); |
| 2149 __ ldr(R1, Address(SP, kStartIndexOffset)); | 2149 __ ldr(R1, Address(SP, kStartIndexOffset)); |
| 2150 __ SmiUntag(R1); | 2150 __ SmiUntag(R1); |
| 2151 __ add(R3, R3, Operand(R1)); | 2151 __ add(R3, R3, Operand(R1)); |
| 2152 // Calculate start address and untag (- 1). | 2152 // Calculate start address and untag (- 1). |
| 2153 __ AddImmediate(R3, R3, OneByteString::data_offset() - 1); | 2153 __ AddImmediate(R3, OneByteString::data_offset() - 1); |
| 2154 | 2154 |
| 2155 // R3: Start address to copy from (untagged). | 2155 // R3: Start address to copy from (untagged). |
| 2156 // R1: Untagged start index. | 2156 // R1: Untagged start index. |
| 2157 __ ldr(R2, Address(SP, kEndIndexOffset)); | 2157 __ ldr(R2, Address(SP, kEndIndexOffset)); |
| 2158 __ SmiUntag(R2); | 2158 __ SmiUntag(R2); |
| 2159 __ sub(R2, R2, Operand(R1)); | 2159 __ sub(R2, R2, Operand(R1)); |
| 2160 | 2160 |
| 2161 // R3: Start address to copy from (untagged). | 2161 // R3: Start address to copy from (untagged). |
| 2162 // R2: Untagged number of bytes to copy. | 2162 // R2: Untagged number of bytes to copy. |
| 2163 // R0: Tagged result string. | 2163 // R0: Tagged result string. |
| 2164 // R6: Pointer into R3. | 2164 // R6: Pointer into R3. |
| 2165 // R7: Pointer into R0. | 2165 // R7: Pointer into R0. |
| 2166 // R1: Scratch register. | 2166 // R1: Scratch register. |
| 2167 Label loop, done; | 2167 Label loop, done; |
| 2168 __ cmp(R2, Operand(0)); | 2168 __ cmp(R2, Operand(0)); |
| 2169 __ b(&done, LE); | 2169 __ b(&done, LE); |
| 2170 __ mov(R6, R3); | 2170 __ mov(R6, R3); |
| 2171 __ mov(R7, R0); | 2171 __ mov(R7, R0); |
| 2172 __ Bind(&loop); | 2172 __ Bind(&loop); |
| 2173 __ ldr(R1, Address(R6), kUnsignedByte); | 2173 __ ldr(R1, Address(R6), kUnsignedByte); |
| 2174 __ AddImmediate(R6, R6, 1); | 2174 __ AddImmediate(R6, 1); |
| 2175 __ sub(R2, R2, Operand(1)); | 2175 __ sub(R2, R2, Operand(1)); |
| 2176 __ cmp(R2, Operand(0)); | 2176 __ cmp(R2, Operand(0)); |
| 2177 __ str(R1, FieldAddress(R7, OneByteString::data_offset()), kUnsignedByte); | 2177 __ str(R1, FieldAddress(R7, OneByteString::data_offset()), kUnsignedByte); |
| 2178 __ AddImmediate(R7, R7, 1); | 2178 __ AddImmediate(R7, 1); |
| 2179 __ b(&loop, GT); | 2179 __ b(&loop, GT); |
| 2180 | 2180 |
| 2181 __ Bind(&done); | 2181 __ Bind(&done); |
| 2182 __ ret(); | 2182 __ ret(); |
| 2183 __ Bind(&fall_through); | 2183 __ Bind(&fall_through); |
| 2184 } | 2184 } |
| 2185 | 2185 |
| 2186 | 2186 |
| 2187 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { | 2187 void Intrinsifier::OneByteStringSetAt(Assembler* assembler) { |
| 2188 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. | 2188 __ ldr(R2, Address(SP, 0 * kWordSize)); // Value. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2231 __ cmp(R2, Operand(R3)); | 2231 __ cmp(R2, Operand(R3)); |
| 2232 __ b(&is_false, NE); | 2232 __ b(&is_false, NE); |
| 2233 | 2233 |
| 2234 // Check contents, no fall-through possible. | 2234 // Check contents, no fall-through possible. |
| 2235 // TODO(zra): try out other sequences. | 2235 // TODO(zra): try out other sequences. |
| 2236 ASSERT((string_cid == kOneByteStringCid) || | 2236 ASSERT((string_cid == kOneByteStringCid) || |
| 2237 (string_cid == kTwoByteStringCid)); | 2237 (string_cid == kTwoByteStringCid)); |
| 2238 const intptr_t offset = (string_cid == kOneByteStringCid) | 2238 const intptr_t offset = (string_cid == kOneByteStringCid) |
| 2239 ? OneByteString::data_offset() | 2239 ? OneByteString::data_offset() |
| 2240 : TwoByteString::data_offset(); | 2240 : TwoByteString::data_offset(); |
| 2241 __ AddImmediate(R0, R0, offset - kHeapObjectTag); | 2241 __ AddImmediate(R0, offset - kHeapObjectTag); |
| 2242 __ AddImmediate(R1, R1, offset - kHeapObjectTag); | 2242 __ AddImmediate(R1, offset - kHeapObjectTag); |
| 2243 __ SmiUntag(R2); | 2243 __ SmiUntag(R2); |
| 2244 __ Bind(&loop); | 2244 __ Bind(&loop); |
| 2245 __ AddImmediate(R2, R2, -1); | 2245 __ AddImmediate(R2, -1); |
| 2246 __ CompareRegisters(R2, ZR); | 2246 __ CompareRegisters(R2, ZR); |
| 2247 __ b(&is_true, LT); | 2247 __ b(&is_true, LT); |
| 2248 if (string_cid == kOneByteStringCid) { | 2248 if (string_cid == kOneByteStringCid) { |
| 2249 __ ldr(R3, Address(R0), kUnsignedByte); | 2249 __ ldr(R3, Address(R0), kUnsignedByte); |
| 2250 __ ldr(R4, Address(R1), kUnsignedByte); | 2250 __ ldr(R4, Address(R1), kUnsignedByte); |
| 2251 __ AddImmediate(R0, R0, 1); | 2251 __ AddImmediate(R0, 1); |
| 2252 __ AddImmediate(R1, R1, 1); | 2252 __ AddImmediate(R1, 1); |
| 2253 } else if (string_cid == kTwoByteStringCid) { | 2253 } else if (string_cid == kTwoByteStringCid) { |
| 2254 __ ldr(R3, Address(R0), kUnsignedHalfword); | 2254 __ ldr(R3, Address(R0), kUnsignedHalfword); |
| 2255 __ ldr(R4, Address(R1), kUnsignedHalfword); | 2255 __ ldr(R4, Address(R1), kUnsignedHalfword); |
| 2256 __ AddImmediate(R0, R0, 2); | 2256 __ AddImmediate(R0, 2); |
| 2257 __ AddImmediate(R1, R1, 2); | 2257 __ AddImmediate(R1, 2); |
| 2258 } else { | 2258 } else { |
| 2259 UNIMPLEMENTED(); | 2259 UNIMPLEMENTED(); |
| 2260 } | 2260 } |
| 2261 __ cmp(R3, Operand(R4)); | 2261 __ cmp(R3, Operand(R4)); |
| 2262 __ b(&is_false, NE); | 2262 __ b(&is_false, NE); |
| 2263 __ b(&loop); | 2263 __ b(&loop); |
| 2264 | 2264 |
| 2265 __ Bind(&is_true); | 2265 __ Bind(&is_true); |
| 2266 __ LoadObject(R0, Bool::True()); | 2266 __ LoadObject(R0, Bool::True()); |
| 2267 __ ret(); | 2267 __ ret(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2295 // Incoming registers: | 2295 // Incoming registers: |
| 2296 // R0: Function. (Will be reloaded with the specialized matcher function.) | 2296 // R0: Function. (Will be reloaded with the specialized matcher function.) |
| 2297 // R4: Arguments descriptor. (Will be preserved.) | 2297 // R4: Arguments descriptor. (Will be preserved.) |
| 2298 // R5: Unknown. (Must be GC safe on tail call.) | 2298 // R5: Unknown. (Must be GC safe on tail call.) |
| 2299 | 2299 |
| 2300 // Load the specialized function pointer into R0. Leverage the fact the | 2300 // Load the specialized function pointer into R0. Leverage the fact the |
| 2301 // string CIDs as well as stored function pointers are in sequence. | 2301 // string CIDs as well as stored function pointers are in sequence. |
| 2302 __ ldr(R2, Address(SP, kRegExpParamOffset)); | 2302 __ ldr(R2, Address(SP, kRegExpParamOffset)); |
| 2303 __ ldr(R1, Address(SP, kStringParamOffset)); | 2303 __ ldr(R1, Address(SP, kStringParamOffset)); |
| 2304 __ LoadClassId(R1, R1); | 2304 __ LoadClassId(R1, R1); |
| 2305 __ AddImmediate(R1, R1, -kOneByteStringCid); | 2305 __ AddImmediate(R1, -kOneByteStringCid); |
| 2306 __ add(R1, R2, Operand(R1, LSL, kWordSizeLog2)); | 2306 __ add(R1, R2, Operand(R1, LSL, kWordSizeLog2)); |
| 2307 __ ldr(R0, | 2307 __ ldr(R0, |
| 2308 FieldAddress(R1, RegExp::function_offset(kOneByteStringCid, sticky))); | 2308 FieldAddress(R1, RegExp::function_offset(kOneByteStringCid, sticky))); |
| 2309 | 2309 |
| 2310 // Registers are now set up for the lazy compile stub. It expects the function | 2310 // Registers are now set up for the lazy compile stub. It expects the function |
| 2311 // in R0, the argument descriptor in R4, and IC-Data in R5. | 2311 // in R0, the argument descriptor in R4, and IC-Data in R5. |
| 2312 __ eor(R5, R5, Operand(R5)); | 2312 __ eor(R5, R5, Operand(R5)); |
| 2313 | 2313 |
| 2314 // Tail-call the function. | 2314 // Tail-call the function. |
| 2315 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | 2315 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2377 | 2377 |
| 2378 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { | 2378 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { |
| 2379 __ ldr(R0, Address(THR, Thread::async_stack_trace_offset())); | 2379 __ ldr(R0, Address(THR, Thread::async_stack_trace_offset())); |
| 2380 __ LoadObject(R0, Object::null_object()); | 2380 __ LoadObject(R0, Object::null_object()); |
| 2381 __ ret(); | 2381 __ ret(); |
| 2382 } | 2382 } |
| 2383 | 2383 |
| 2384 } // namespace dart | 2384 } // namespace dart |
| 2385 | 2385 |
| 2386 #endif // defined TARGET_ARCH_ARM64 | 2386 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |