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