• 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/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