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