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