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 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 __ tsti(R2, Immediate(kSmiTagMask)); \ | 189 __ tsti(R2, Immediate(kSmiTagMask)); \ |
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_plus_alignment_padding = \ |
200 __ AddImmediate(R2, fixed_size); \ | 200 sizeof(Raw##type_name) + kObjectAlignment - 1; \ |
| 201 __ AddImmediate(R2, fixed_size_plus_alignment_padding); \ |
201 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \ | 202 __ andi(R2, R2, Immediate(~(kObjectAlignment - 1))); \ |
202 Heap::Space space = Heap::kNew; \ | 203 Heap::Space space = Heap::kNew; \ |
203 __ ldr(R3, Address(THR, Thread::heap_offset())); \ | 204 __ ldr(R3, Address(THR, Thread::heap_offset())); \ |
204 __ ldr(R0, Address(R3, Heap::TopOffset(space))); \ | 205 __ ldr(R0, Address(R3, Heap::TopOffset(space))); \ |
205 \ | 206 \ |
206 /* R2: allocation size. */ \ | 207 /* R2: allocation size. */ \ |
207 __ adds(R1, R0, Operand(R2)); \ | 208 __ adds(R1, R0, Operand(R2)); \ |
208 __ b(&fall_through, CS); /* Fail on unsigned overflow. */ \ | 209 __ b(&fall_through, CS); /* Fail on unsigned overflow. */ \ |
209 \ | 210 \ |
210 /* Check if the allocation fits into the remaining space. */ \ | 211 /* Check if the allocation fits into the remaining space. */ \ |
(...skipping 1604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1815 __ LoadObject(R0, Bool::False()); | 1816 __ LoadObject(R0, Bool::False()); |
1816 __ ret(); | 1817 __ ret(); |
1817 | 1818 |
1818 __ Bind(&fall_through); | 1819 __ Bind(&fall_through); |
1819 } | 1820 } |
1820 | 1821 |
1821 | 1822 |
1822 void Intrinsifier::String_getHashCode(Assembler* assembler) { | 1823 void Intrinsifier::String_getHashCode(Assembler* assembler) { |
1823 Label fall_through; | 1824 Label fall_through; |
1824 __ ldr(R0, Address(SP, 0 * kWordSize)); | 1825 __ ldr(R0, Address(SP, 0 * kWordSize)); |
1825 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | 1826 __ ldr(R0, FieldAddress(R0, String::hash_offset()), kUnsignedWord); |
1826 __ CompareRegisters(R0, ZR); | 1827 __ adds(R0, R0, Operand(R0)); // Smi tag the hash code, setting Z flag. |
1827 __ b(&fall_through, EQ); | 1828 __ b(&fall_through, EQ); |
1828 __ ret(); | 1829 __ ret(); |
1829 // Hash not yet computed. | 1830 // Hash not yet computed. |
1830 __ Bind(&fall_through); | 1831 __ Bind(&fall_through); |
1831 } | 1832 } |
1832 | 1833 |
1833 | 1834 |
1834 void GenerateSubstringMatchesSpecialization(Assembler* assembler, | 1835 void GenerateSubstringMatchesSpecialization(Assembler* assembler, |
1835 intptr_t receiver_cid, | 1836 intptr_t receiver_cid, |
1836 intptr_t other_cid, | 1837 intptr_t other_cid, |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1988 __ LoadObject(R0, Bool::True()); | 1989 __ LoadObject(R0, Bool::True()); |
1989 __ LoadObject(TMP, Bool::False()); | 1990 __ LoadObject(TMP, Bool::False()); |
1990 __ csel(R0, TMP, R0, NE); | 1991 __ csel(R0, TMP, R0, NE); |
1991 __ ret(); | 1992 __ ret(); |
1992 } | 1993 } |
1993 | 1994 |
1994 | 1995 |
1995 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { | 1996 void Intrinsifier::OneByteString_getHashCode(Assembler* assembler) { |
1996 Label compute_hash; | 1997 Label compute_hash; |
1997 __ ldr(R1, Address(SP, 0 * kWordSize)); // OneByteString object. | 1998 __ ldr(R1, Address(SP, 0 * kWordSize)); // OneByteString object. |
1998 __ ldr(R0, FieldAddress(R1, String::hash_offset())); | 1999 __ ldr(R0, FieldAddress(R1, String::hash_offset()), kUnsignedWord); |
1999 __ CompareRegisters(R0, ZR); | 2000 __ adds(R0, R0, Operand(R0)); // Smi tag the hash code, setting Z flag. |
2000 __ b(&compute_hash, EQ); | 2001 __ b(&compute_hash, EQ); |
2001 __ ret(); // Return if already computed. | 2002 __ ret(); // Return if already computed. |
2002 | 2003 |
2003 __ Bind(&compute_hash); | 2004 __ Bind(&compute_hash); |
2004 __ ldr(R2, FieldAddress(R1, String::length_offset())); | 2005 __ ldr(R2, FieldAddress(R1, String::length_offset())); |
2005 __ SmiUntag(R2); | 2006 __ SmiUntag(R2); |
2006 | 2007 |
2007 Label done; | 2008 Label done; |
2008 // If the string is empty, set the hash to 1, and return. | 2009 // If the string is empty, set the hash to 1, and return. |
2009 __ CompareRegisters(R2, ZR); | 2010 __ CompareRegisters(R2, ZR); |
(...skipping 29 matching lines...) Expand all Loading... |
2039 // hash_ += hash_ << 15; | 2040 // hash_ += hash_ << 15; |
2040 __ addw(R0, R0, Operand(R0, LSL, 3)); | 2041 __ addw(R0, R0, Operand(R0, LSL, 3)); |
2041 __ eorw(R0, R0, Operand(R0, LSR, 11)); | 2042 __ eorw(R0, R0, Operand(R0, LSR, 11)); |
2042 __ addw(R0, R0, Operand(R0, LSL, 15)); | 2043 __ addw(R0, R0, Operand(R0, LSL, 15)); |
2043 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); | 2044 // hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1); |
2044 __ AndImmediate(R0, R0, (static_cast<intptr_t>(1) << String::kHashBits) - 1); | 2045 __ AndImmediate(R0, R0, (static_cast<intptr_t>(1) << String::kHashBits) - 1); |
2045 __ CompareRegisters(R0, ZR); | 2046 __ CompareRegisters(R0, ZR); |
2046 // return hash_ == 0 ? 1 : hash_; | 2047 // return hash_ == 0 ? 1 : hash_; |
2047 __ Bind(&done); | 2048 __ Bind(&done); |
2048 __ csinc(R0, R0, ZR, NE); // R0 <- (R0 != 0) ? R0 : (ZR + 1). | 2049 __ csinc(R0, R0, ZR, NE); // R0 <- (R0 != 0) ? R0 : (ZR + 1). |
| 2050 __ str(R0, FieldAddress(R1, String::hash_offset()), kUnsignedWord); |
2049 __ SmiTag(R0); | 2051 __ SmiTag(R0); |
2050 __ str(R0, FieldAddress(R1, String::hash_offset())); | |
2051 __ ret(); | 2052 __ ret(); |
2052 } | 2053 } |
2053 | 2054 |
2054 | 2055 |
2055 // Allocates one-byte string of length 'end - start'. The content is not | 2056 // Allocates one-byte string of length 'end - start'. The content is not |
2056 // initialized. | 2057 // initialized. |
2057 // 'length-reg' (R2) contains tagged length. | 2058 // 'length-reg' (R2) contains tagged length. |
2058 // Returns new string as tagged pointer in R0. | 2059 // Returns new string as tagged pointer in R0. |
2059 static void TryAllocateOnebyteString(Assembler* assembler, | 2060 static void TryAllocateOnebyteString(Assembler* assembler, |
2060 Label* ok, | 2061 Label* ok, |
2061 Label* failure) { | 2062 Label* failure) { |
2062 const Register length_reg = R2; | 2063 const Register length_reg = R2; |
2063 Label fail; | 2064 Label fail; |
2064 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, R0, failure)); | 2065 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kOneByteStringCid, R0, failure)); |
2065 __ mov(R6, length_reg); // Save the length register. | 2066 __ mov(R6, length_reg); // Save the length register. |
2066 // TODO(koda): Protect against negative length and overflow here. | 2067 // TODO(koda): Protect against negative length and overflow here. |
2067 __ SmiUntag(length_reg); | 2068 __ adds(length_reg, ZR, Operand(length_reg, ASR, kSmiTagSize)); // Smi untag. |
2068 const intptr_t fixed_size = sizeof(RawString) + kObjectAlignment - 1; | 2069 // If the length is 0 then we have to make the allocated size a bit bigger, |
2069 __ AddImmediate(length_reg, fixed_size); | 2070 // otherwise the string takes up less space than an ExternalOneByteString, |
| 2071 // and cannot be externalized. TODO(erikcorry): We should probably just |
| 2072 // return a static zero length string here instead. |
| 2073 // length <- (length != 0) ? length : (ZR + 1). |
| 2074 __ csinc(length_reg, length_reg, ZR, NE); |
| 2075 const intptr_t fixed_size_plus_alignment_padding = |
| 2076 sizeof(RawString) + kObjectAlignment - 1; |
| 2077 __ AddImmediate(length_reg, fixed_size_plus_alignment_padding); |
2070 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); | 2078 __ andi(length_reg, length_reg, Immediate(~(kObjectAlignment - 1))); |
2071 | 2079 |
2072 const intptr_t cid = kOneByteStringCid; | 2080 const intptr_t cid = kOneByteStringCid; |
2073 Heap::Space space = Heap::kNew; | 2081 Heap::Space space = Heap::kNew; |
2074 __ ldr(R3, Address(THR, Thread::heap_offset())); | 2082 __ ldr(R3, Address(THR, Thread::heap_offset())); |
2075 __ ldr(R0, Address(R3, Heap::TopOffset(space))); | 2083 __ ldr(R0, Address(R3, Heap::TopOffset(space))); |
2076 | 2084 |
2077 // length_reg: allocation size. | 2085 // length_reg: allocation size. |
2078 __ adds(R1, R0, Operand(length_reg)); | 2086 __ adds(R1, R0, Operand(length_reg)); |
2079 __ b(&fail, CS); // Fail on unsigned overflow. | 2087 __ b(&fail, CS); // Fail on unsigned overflow. |
(...skipping 19 matching lines...) Expand all Loading... |
2099 // R2: allocation size. | 2107 // R2: allocation size. |
2100 { | 2108 { |
2101 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; | 2109 const intptr_t shift = RawObject::kSizeTagPos - kObjectAlignmentLog2; |
2102 | 2110 |
2103 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); | 2111 __ CompareImmediate(R2, RawObject::SizeTag::kMaxSizeTag); |
2104 __ LslImmediate(R2, R2, shift); | 2112 __ LslImmediate(R2, R2, shift); |
2105 __ csel(R2, R2, ZR, LS); | 2113 __ csel(R2, R2, ZR, LS); |
2106 | 2114 |
2107 // Get the class index and insert it into the tags. | 2115 // Get the class index and insert it into the tags. |
2108 // R2: size and bit tags. | 2116 // R2: size and bit tags. |
| 2117 // This also clears the hash, which is in the high word of the tags. |
2109 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); | 2118 __ LoadImmediate(TMP, RawObject::ClassIdTag::encode(cid)); |
2110 __ orr(R2, R2, Operand(TMP)); | 2119 __ orr(R2, R2, Operand(TMP)); |
2111 __ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags. | 2120 __ str(R2, FieldAddress(R0, String::tags_offset())); // Store tags. |
2112 } | 2121 } |
2113 | 2122 |
2114 // Set the length field using the saved length (R6). | 2123 // Set the length field using the saved length (R6). |
2115 __ StoreIntoObjectNoBarrier(R0, FieldAddress(R0, String::length_offset()), | 2124 __ StoreIntoObjectNoBarrier(R0, FieldAddress(R0, String::length_offset()), |
2116 R6); | 2125 R6); |
2117 // Clear hash. | |
2118 __ mov(TMP, ZR); | |
2119 __ str(TMP, FieldAddress(R0, String::hash_offset())); | |
2120 __ b(ok); | 2126 __ b(ok); |
2121 | 2127 |
2122 __ Bind(&fail); | 2128 __ Bind(&fail); |
2123 __ b(failure); | 2129 __ b(failure); |
2124 } | 2130 } |
2125 | 2131 |
2126 | 2132 |
2127 // Arg0: OneByteString (receiver). | 2133 // Arg0: OneByteString (receiver). |
2128 // Arg1: Start index as Smi. | 2134 // Arg1: Start index as Smi. |
2129 // Arg2: End index as Smi. | 2135 // Arg2: End index as Smi. |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2377 | 2383 |
2378 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { | 2384 void Intrinsifier::SetAsyncThreadStackTrace(Assembler* assembler) { |
2379 __ ldr(R0, Address(THR, Thread::async_stack_trace_offset())); | 2385 __ ldr(R0, Address(THR, Thread::async_stack_trace_offset())); |
2380 __ LoadObject(R0, Object::null_object()); | 2386 __ LoadObject(R0, Object::null_object()); |
2381 __ ret(); | 2387 __ ret(); |
2382 } | 2388 } |
2383 | 2389 |
2384 } // namespace dart | 2390 } // namespace dart |
2385 | 2391 |
2386 #endif // defined TARGET_ARCH_ARM64 | 2392 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |