1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #ifndef ART_RUNTIME_MIRROR_STRING_INL_H_ 17 #define ART_RUNTIME_MIRROR_STRING_INL_H_ 18 19 #include "string.h" 20 21 #include "android-base/stringprintf.h" 22 23 #include "array.h" 24 #include "base/bit_utils.h" 25 #include "base/globals.h" 26 #include "base/utils.h" 27 #include "class.h" 28 #include "common_throws.h" 29 #include "dex/utf.h" 30 #include "gc/heap-inl.h" 31 #include "runtime.h" 32 #include "thread.h" 33 34 namespace art { 35 namespace mirror { 36 37 inline uint32_t String::ClassSize(PointerSize pointer_size) { 38 #ifdef USE_D8_DESUGAR 39 // Two lambdas in CharSequence: 40 // lambda$chars$0$CharSequence 41 // lambda$codePoints$1$CharSequence 42 // which were virtual functions in standalone desugar, becomes 43 // direct functions with D8 desugaring. 44 uint32_t vtable_entries = Object::kVTableLength + 54; 45 #else 46 uint32_t vtable_entries = Object::kVTableLength + 56; 47 #endif 48 return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 1, 2, pointer_size); 49 } 50 51 // Sets string count in the allocation code path to ensure it is guarded by a CAS. 52 class SetStringCountVisitor { 53 public: 54 explicit SetStringCountVisitor(int32_t count) : count_(count) { 55 } 56 57 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const 58 REQUIRES_SHARED(Locks::mutator_lock_) { 59 // Avoid AsString as object is not yet in live bitmap or allocation stack. 60 ObjPtr<String> string = ObjPtr<String>::DownCast(obj); 61 string->SetCount(count_); 62 DCHECK(!string->IsCompressed() || kUseStringCompression); 63 } 64 65 private: 66 const int32_t count_; 67 }; 68 69 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS. 70 class SetStringCountAndBytesVisitor { 71 public: 72 SetStringCountAndBytesVisitor(int32_t count, Handle<ByteArray> src_array, int32_t offset, 73 int32_t high_byte) 74 : count_(count), src_array_(src_array), offset_(offset), high_byte_(high_byte) { 75 } 76 77 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const 78 REQUIRES_SHARED(Locks::mutator_lock_) { 79 // Avoid AsString as object is not yet in live bitmap or allocation stack. 80 ObjPtr<String> string = ObjPtr<String>::DownCast(obj); 81 string->SetCount(count_); 82 DCHECK(!string->IsCompressed() || kUseStringCompression); 83 int32_t length = String::GetLengthFromCount(count_); 84 const uint8_t* const src = reinterpret_cast<uint8_t*>(src_array_->GetData()) + offset_; 85 if (string->IsCompressed()) { 86 uint8_t* valueCompressed = string->GetValueCompressed(); 87 for (int i = 0; i < length; i++) { 88 valueCompressed[i] = (src[i] & 0xFF); 89 } 90 } else { 91 uint16_t* value = string->GetValue(); 92 for (int i = 0; i < length; i++) { 93 value[i] = high_byte_ + (src[i] & 0xFF); 94 } 95 } 96 } 97 98 private: 99 const int32_t count_; 100 Handle<ByteArray> src_array_; 101 const int32_t offset_; 102 const int32_t high_byte_; 103 }; 104 105 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS. 106 class SetStringCountAndValueVisitorFromCharArray { 107 public: 108 SetStringCountAndValueVisitorFromCharArray(int32_t count, Handle<CharArray> src_array, 109 int32_t offset) : 110 count_(count), src_array_(src_array), offset_(offset) { 111 } 112 113 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const 114 REQUIRES_SHARED(Locks::mutator_lock_) { 115 // Avoid AsString as object is not yet in live bitmap or allocation stack. 116 ObjPtr<String> string = ObjPtr<String>::DownCast(obj); 117 string->SetCount(count_); 118 const uint16_t* const src = src_array_->GetData() + offset_; 119 const int32_t length = String::GetLengthFromCount(count_); 120 if (kUseStringCompression && String::IsCompressed(count_)) { 121 for (int i = 0; i < length; ++i) { 122 string->GetValueCompressed()[i] = static_cast<uint8_t>(src[i]); 123 } 124 } else { 125 memcpy(string->GetValue(), src, length * sizeof(uint16_t)); 126 } 127 } 128 129 private: 130 const int32_t count_; 131 Handle<CharArray> src_array_; 132 const int32_t offset_; 133 }; 134 135 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS. 136 class SetStringCountAndValueVisitorFromString { 137 public: 138 SetStringCountAndValueVisitorFromString(int32_t count, 139 Handle<String> src_string, 140 int32_t offset) : 141 count_(count), src_string_(src_string), offset_(offset) { 142 } 143 144 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const 145 REQUIRES_SHARED(Locks::mutator_lock_) { 146 // Avoid AsString as object is not yet in live bitmap or allocation stack. 147 ObjPtr<String> string = ObjPtr<String>::DownCast(obj); 148 string->SetCount(count_); 149 const int32_t length = String::GetLengthFromCount(count_); 150 bool compressible = kUseStringCompression && String::IsCompressed(count_); 151 if (src_string_->IsCompressed()) { 152 const uint8_t* const src = src_string_->GetValueCompressed() + offset_; 153 memcpy(string->GetValueCompressed(), src, length * sizeof(uint8_t)); 154 } else { 155 const uint16_t* const src = src_string_->GetValue() + offset_; 156 if (compressible) { 157 for (int i = 0; i < length; ++i) { 158 string->GetValueCompressed()[i] = static_cast<uint8_t>(src[i]); 159 } 160 } else { 161 memcpy(string->GetValue(), src, length * sizeof(uint16_t)); 162 } 163 } 164 } 165 166 private: 167 const int32_t count_; 168 Handle<String> src_string_; 169 const int32_t offset_; 170 }; 171 172 inline uint16_t String::CharAt(int32_t index) { 173 int32_t count = GetLength(); 174 if (UNLIKELY((index < 0) || (index >= count))) { 175 ThrowStringIndexOutOfBoundsException(index, count); 176 return 0; 177 } 178 if (IsCompressed()) { 179 return GetValueCompressed()[index]; 180 } else { 181 return GetValue()[index]; 182 } 183 } 184 185 template <typename MemoryType> 186 int32_t String::FastIndexOf(MemoryType* chars, int32_t ch, int32_t start) { 187 const MemoryType* p = chars + start; 188 const MemoryType* end = chars + GetLength(); 189 while (p < end) { 190 if (*p++ == ch) { 191 return (p - 1) - chars; 192 } 193 } 194 return -1; 195 } 196 197 template<VerifyObjectFlags kVerifyFlags> 198 inline size_t String::SizeOf() { 199 size_t size = sizeof(String); 200 if (IsCompressed()) { 201 size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); 202 } else { 203 size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); 204 } 205 // String.equals() intrinsics assume zero-padding up to kObjectAlignment, 206 // so make sure the zero-padding is actually copied around if GC compaction 207 // chooses to copy only SizeOf() bytes. 208 // http://b/23528461 209 return RoundUp(size, kObjectAlignment); 210 } 211 212 template <bool kIsInstrumented, typename PreFenceVisitor> 213 inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, 214 gc::AllocatorType allocator_type, 215 const PreFenceVisitor& pre_fence_visitor) { 216 constexpr size_t header_size = sizeof(String); 217 const bool compressible = kUseStringCompression && String::IsCompressed(utf16_length_with_flag); 218 const size_t block_size = (compressible) ? sizeof(uint8_t) : sizeof(uint16_t); 219 size_t length = String::GetLengthFromCount(utf16_length_with_flag); 220 static_assert(sizeof(length) <= sizeof(size_t), 221 "static_cast<size_t>(utf16_length) must not lose bits."); 222 size_t data_size = block_size * length; 223 size_t size = header_size + data_size; 224 // String.equals() intrinsics assume zero-padding up to kObjectAlignment, 225 // so make sure the allocator clears the padding as well. 226 // http://b/23528461 227 size_t alloc_size = RoundUp(size, kObjectAlignment); 228 229 Class* string_class = GetJavaLangString(); 230 // Check for overflow and throw OutOfMemoryError if this was an unreasonable request. 231 // Do this by comparing with the maximum length that will _not_ cause an overflow. 232 const size_t overflow_length = (-header_size) / block_size; // Unsigned arithmetic. 233 const size_t max_alloc_length = overflow_length - 1u; 234 static_assert(IsAligned<sizeof(uint16_t)>(kObjectAlignment), 235 "kObjectAlignment must be at least as big as Java char alignment"); 236 const size_t max_length = RoundDown(max_alloc_length, kObjectAlignment / block_size); 237 if (UNLIKELY(length > max_length)) { 238 self->ThrowOutOfMemoryError( 239 android::base::StringPrintf("%s of length %d would overflow", 240 Class::PrettyDescriptor(string_class).c_str(), 241 static_cast<int>(length)).c_str()); 242 return nullptr; 243 } 244 245 gc::Heap* heap = Runtime::Current()->GetHeap(); 246 return down_cast<String*>( 247 heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, string_class, alloc_size, 248 allocator_type, pre_fence_visitor)); 249 } 250 251 template <bool kIsInstrumented> 252 inline String* String::AllocEmptyString(Thread* self, gc::AllocatorType allocator_type) { 253 const int32_t length_with_flag = String::GetFlaggedCount(0, /* compressible */ true); 254 SetStringCountVisitor visitor(length_with_flag); 255 return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor); 256 } 257 258 template <bool kIsInstrumented> 259 inline String* String::AllocFromByteArray(Thread* self, int32_t byte_length, 260 Handle<ByteArray> array, int32_t offset, 261 int32_t high_byte, gc::AllocatorType allocator_type) { 262 const uint8_t* const src = reinterpret_cast<uint8_t*>(array->GetData()) + offset; 263 high_byte &= 0xff; // Extract the relevant bits before determining `compressible`. 264 const bool compressible = 265 kUseStringCompression && String::AllASCII<uint8_t>(src, byte_length) && (high_byte == 0); 266 const int32_t length_with_flag = String::GetFlaggedCount(byte_length, compressible); 267 SetStringCountAndBytesVisitor visitor(length_with_flag, array, offset, high_byte << 8); 268 String* string = Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor); 269 return string; 270 } 271 272 template <bool kIsInstrumented> 273 inline String* String::AllocFromCharArray(Thread* self, int32_t count, 274 Handle<CharArray> array, int32_t offset, 275 gc::AllocatorType allocator_type) { 276 // It is a caller error to have a count less than the actual array's size. 277 DCHECK_GE(array->GetLength(), count); 278 const bool compressible = kUseStringCompression && 279 String::AllASCII<uint16_t>(array->GetData() + offset, count); 280 const int32_t length_with_flag = String::GetFlaggedCount(count, compressible); 281 SetStringCountAndValueVisitorFromCharArray visitor(length_with_flag, array, offset); 282 String* new_string = Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor); 283 return new_string; 284 } 285 286 template <bool kIsInstrumented> 287 inline String* String::AllocFromString(Thread* self, int32_t string_length, Handle<String> string, 288 int32_t offset, gc::AllocatorType allocator_type) { 289 const bool compressible = kUseStringCompression && 290 ((string->IsCompressed()) ? true : String::AllASCII<uint16_t>(string->GetValue() + offset, 291 string_length)); 292 const int32_t length_with_flag = String::GetFlaggedCount(string_length, compressible); 293 SetStringCountAndValueVisitorFromString visitor(length_with_flag, string, offset); 294 String* new_string = Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor); 295 return new_string; 296 } 297 298 inline int32_t String::GetHashCode() { 299 int32_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_)); 300 if (UNLIKELY(result == 0)) { 301 result = ComputeHashCode(); 302 } 303 if (kIsDebugBuild) { 304 if (IsCompressed()) { 305 DCHECK(result != 0 || ComputeUtf16Hash(GetValueCompressed(), GetLength()) == 0) 306 << ToModifiedUtf8() << " " << result; 307 } else { 308 DCHECK(result != 0 || ComputeUtf16Hash(GetValue(), GetLength()) == 0) 309 << ToModifiedUtf8() << " " << result; 310 } 311 } 312 return result; 313 } 314 315 template<typename MemoryType> 316 inline bool String::AllASCII(const MemoryType* chars, const int length) { 317 static_assert(std::is_unsigned<MemoryType>::value, "Expecting unsigned MemoryType"); 318 for (int i = 0; i < length; ++i) { 319 if (!IsASCII(chars[i])) { 320 return false; 321 } 322 } 323 return true; 324 } 325 326 inline bool String::DexFileStringAllASCII(const char* chars, const int length) { 327 // For strings from the dex file we just need to check that 328 // the terminating character is at the right position. 329 DCHECK_EQ(AllASCII(reinterpret_cast<const uint8_t*>(chars), length), chars[length] == 0); 330 return chars[length] == 0; 331 } 332 333 } // namespace mirror 334 } // namespace art 335 336 #endif // ART_RUNTIME_MIRROR_STRING_INL_H_ 337