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