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/stringprintf.h"
22
23 #include "array.h"
24 #include "base/bit_utils.h"
25 #include "class.h"
26 #include "class_root-inl.h"
27 #include "gc/allocator_type.h"
28 #include "gc/heap-inl.h"
29 #include "obj_ptr.h"
30 #include "runtime.h"
31 #include "runtime_globals.h"
32 #include "thread.h"
33
34 namespace art {
35 namespace mirror {
36
37 // Sets string count in the allocation code path to ensure it is guarded by a CAS.
38 class SetStringCountVisitor {
39 public:
SetStringCountVisitor(int32_t count)40 explicit SetStringCountVisitor(int32_t count) : count_(count) {
41 }
42
operator()43 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const
44 REQUIRES_SHARED(Locks::mutator_lock_) {
45 // Avoid AsString as object is not yet in live bitmap or allocation stack.
46 ObjPtr<String> string = ObjPtr<String>::DownCast(obj);
47 string->SetCount(count_);
48 DCHECK(!string->IsCompressed() || kUseStringCompression);
49 }
50
51 private:
52 const int32_t count_;
53 };
54
55 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS.
56 class SetStringCountAndBytesVisitor {
57 public:
SetStringCountAndBytesVisitor(int32_t count,Handle<ByteArray> src_array,int32_t offset,int32_t high_byte)58 SetStringCountAndBytesVisitor(int32_t count, Handle<ByteArray> src_array, int32_t offset,
59 int32_t high_byte)
60 : count_(count), src_array_(src_array), offset_(offset), high_byte_(high_byte) {
61 }
62
operator()63 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const
64 REQUIRES_SHARED(Locks::mutator_lock_) {
65 // Avoid AsString as object is not yet in live bitmap or allocation stack.
66 ObjPtr<String> string = ObjPtr<String>::DownCast(obj);
67 string->SetCount(count_);
68 DCHECK(!string->IsCompressed() || kUseStringCompression);
69 int32_t length = String::GetLengthFromCount(count_);
70 const uint8_t* const src = reinterpret_cast<uint8_t*>(src_array_->GetData()) + offset_;
71 if (string->IsCompressed()) {
72 uint8_t* valueCompressed = string->GetValueCompressed();
73 for (int i = 0; i < length; i++) {
74 valueCompressed[i] = (src[i] & 0xFF);
75 }
76 } else {
77 uint16_t* value = string->GetValue();
78 for (int i = 0; i < length; i++) {
79 value[i] = high_byte_ + (src[i] & 0xFF);
80 }
81 }
82 }
83
84 private:
85 const int32_t count_;
86 Handle<ByteArray> src_array_;
87 const int32_t offset_;
88 const int32_t high_byte_;
89 };
90
91 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS.
92 class SetStringCountAndValueVisitorFromCharArray {
93 public:
SetStringCountAndValueVisitorFromCharArray(int32_t count,Handle<CharArray> src_array,int32_t offset)94 SetStringCountAndValueVisitorFromCharArray(int32_t count, Handle<CharArray> src_array,
95 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 const uint16_t* const src = src_array_->GetData() + offset_;
105 const int32_t length = String::GetLengthFromCount(count_);
106 if (kUseStringCompression && String::IsCompressed(count_)) {
107 for (int i = 0; i < length; ++i) {
108 string->GetValueCompressed()[i] = static_cast<uint8_t>(src[i]);
109 }
110 } else {
111 memcpy(string->GetValue(), src, length * sizeof(uint16_t));
112 }
113 }
114
115 private:
116 const int32_t count_;
117 Handle<CharArray> src_array_;
118 const int32_t offset_;
119 };
120
121 // Sets string count and value in the allocation code path to ensure it is guarded by a CAS.
122 class SetStringCountAndValueVisitorFromString {
123 public:
SetStringCountAndValueVisitorFromString(int32_t count,Handle<String> src_string,int32_t offset)124 SetStringCountAndValueVisitorFromString(int32_t count,
125 Handle<String> src_string,
126 int32_t offset) :
127 count_(count), src_string_(src_string), offset_(offset) {
128 }
129
operator()130 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const
131 REQUIRES_SHARED(Locks::mutator_lock_) {
132 // Avoid AsString as object is not yet in live bitmap or allocation stack.
133 ObjPtr<String> string = ObjPtr<String>::DownCast(obj);
134 string->SetCount(count_);
135 const int32_t length = String::GetLengthFromCount(count_);
136 bool compressible = kUseStringCompression && String::IsCompressed(count_);
137 if (src_string_->IsCompressed()) {
138 const uint8_t* const src = src_string_->GetValueCompressed() + offset_;
139 memcpy(string->GetValueCompressed(), src, length * sizeof(uint8_t));
140 } else {
141 const uint16_t* const src = src_string_->GetValue() + offset_;
142 if (compressible) {
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
152 private:
153 const int32_t count_;
154 Handle<String> src_string_;
155 const int32_t offset_;
156 };
157
158 template <bool kIsInstrumented, typename PreFenceVisitor>
Alloc(Thread * self,int32_t utf16_length_with_flag,gc::AllocatorType allocator_type,const PreFenceVisitor & pre_fence_visitor)159 inline ObjPtr<String> String::Alloc(Thread* self,
160 int32_t utf16_length_with_flag,
161 gc::AllocatorType allocator_type,
162 const PreFenceVisitor& pre_fence_visitor) {
163 constexpr size_t header_size = sizeof(String);
164 const bool compressible = kUseStringCompression && String::IsCompressed(utf16_length_with_flag);
165 const size_t block_size = (compressible) ? sizeof(uint8_t) : sizeof(uint16_t);
166 size_t length = String::GetLengthFromCount(utf16_length_with_flag);
167 static_assert(sizeof(length) <= sizeof(size_t),
168 "static_cast<size_t>(utf16_length) must not lose bits.");
169 size_t data_size = block_size * length;
170 size_t size = header_size + data_size;
171 // String.equals() intrinsics assume zero-padding up to kObjectAlignment,
172 // so make sure the allocator clears the padding as well.
173 // http://b/23528461
174 size_t alloc_size = RoundUp(size, kObjectAlignment);
175
176 Runtime* runtime = Runtime::Current();
177 ObjPtr<Class> string_class = GetClassRoot<String>(runtime->GetClassLinker());
178 // Check for overflow and throw OutOfMemoryError if this was an unreasonable request.
179 // Do this by comparing with the maximum length that will _not_ cause an overflow.
180 const size_t overflow_length = (-header_size) / block_size; // Unsigned arithmetic.
181 const size_t max_alloc_length = overflow_length - 1u;
182 static_assert(IsAligned<sizeof(uint16_t)>(kObjectAlignment),
183 "kObjectAlignment must be at least as big as Java char alignment");
184 const size_t max_length = RoundDown(max_alloc_length, kObjectAlignment / block_size);
185 if (UNLIKELY(length > max_length)) {
186 self->ThrowOutOfMemoryError(
187 android::base::StringPrintf("%s of length %d would overflow",
188 Class::PrettyDescriptor(string_class).c_str(),
189 static_cast<int>(length)).c_str());
190 return nullptr;
191 }
192
193 gc::Heap* heap = runtime->GetHeap();
194 return ObjPtr<String>::DownCast(
195 heap->AllocObjectWithAllocator<kIsInstrumented>(self,
196 string_class,
197 alloc_size,
198 allocator_type,
199 pre_fence_visitor));
200 }
201
202 template <bool kIsInstrumented>
AllocEmptyString(Thread * self,gc::AllocatorType allocator_type)203 inline ObjPtr<String> String::AllocEmptyString(Thread* self, gc::AllocatorType allocator_type) {
204 const int32_t length_with_flag = String::GetFlaggedCount(0, /* compressible= */ true);
205 SetStringCountVisitor visitor(length_with_flag);
206 return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor);
207 }
208
209 template <bool kIsInstrumented>
AllocFromByteArray(Thread * self,int32_t byte_length,Handle<ByteArray> array,int32_t offset,int32_t high_byte,gc::AllocatorType allocator_type)210 inline ObjPtr<String> String::AllocFromByteArray(Thread* self,
211 int32_t byte_length,
212 Handle<ByteArray> array,
213 int32_t offset,
214 int32_t high_byte,
215 gc::AllocatorType allocator_type) {
216 const uint8_t* const src = reinterpret_cast<uint8_t*>(array->GetData()) + offset;
217 high_byte &= 0xff; // Extract the relevant bits before determining `compressible`.
218 const bool compressible =
219 kUseStringCompression && String::AllASCII<uint8_t>(src, byte_length) && (high_byte == 0);
220 const int32_t length_with_flag = String::GetFlaggedCount(byte_length, compressible);
221 SetStringCountAndBytesVisitor visitor(length_with_flag, array, offset, high_byte << 8);
222 return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor);
223 }
224
225 template <bool kIsInstrumented>
AllocFromCharArray(Thread * self,int32_t count,Handle<CharArray> array,int32_t offset,gc::AllocatorType allocator_type)226 inline ObjPtr<String> String::AllocFromCharArray(Thread* self,
227 int32_t count,
228 Handle<CharArray> array,
229 int32_t offset,
230 gc::AllocatorType allocator_type) {
231 // It is a caller error to have a count less than the actual array's size.
232 DCHECK_GE(array->GetLength(), count);
233 const bool compressible = kUseStringCompression &&
234 String::AllASCII<uint16_t>(array->GetData() + offset, count);
235 const int32_t length_with_flag = String::GetFlaggedCount(count, compressible);
236 SetStringCountAndValueVisitorFromCharArray visitor(length_with_flag, array, offset);
237 return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor);
238 }
239
240 template <bool kIsInstrumented>
AllocFromString(Thread * self,int32_t string_length,Handle<String> string,int32_t offset,gc::AllocatorType allocator_type)241 inline ObjPtr<String> String::AllocFromString(Thread* self,
242 int32_t string_length,
243 Handle<String> string,
244 int32_t offset,
245 gc::AllocatorType allocator_type) {
246 const bool compressible = kUseStringCompression &&
247 ((string->IsCompressed()) ? true : String::AllASCII<uint16_t>(string->GetValue() + offset,
248 string_length));
249 const int32_t length_with_flag = String::GetFlaggedCount(string_length, compressible);
250 SetStringCountAndValueVisitorFromString visitor(length_with_flag, string, offset);
251 return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor);
252 }
253
254 } // namespace mirror
255 } // namespace art
256
257 #endif // ART_RUNTIME_MIRROR_STRING_ALLOC_INL_H_
258