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