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