• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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