array-inl.h revision a55cf41c9d1da7ee8b2f63974dedfb484042dd03
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
17#ifndef ART_RUNTIME_MIRROR_ARRAY_INL_H_
18#define ART_RUNTIME_MIRROR_ARRAY_INL_H_
19
20#include "array.h"
21
22#include "class.h"
23#include "gc/heap-inl.h"
24#include "thread.h"
25#include "utils.h"
26
27namespace art {
28namespace mirror {
29
30static inline size_t HeaderSize(size_t component_size) {
31  return sizeof(Object) + (component_size == sizeof(int64_t) ? 8 : 4);
32}
33
34template<VerifyObjectFlags kVerifyFlags>
35inline size_t Array::SizeOf() {
36  // This is safe from overflow because the array was already allocated, so we know it's sane.
37  size_t component_size = GetClass<kVerifyFlags>()->GetComponentSize();
38  // Don't need to check this since we already check this in GetClass.
39  int32_t component_count =
40      GetLength<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>();
41  size_t header_size = HeaderSize(component_size);
42  size_t data_size = component_count * component_size;
43  return header_size + data_size;
44}
45
46static inline size_t ComputeArraySize(Thread* self, Class* array_class, int32_t component_count,
47                                      size_t component_size)
48    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
49  DCHECK(array_class != NULL);
50  DCHECK_GE(component_count, 0);
51  DCHECK(array_class->IsArrayClass());
52
53  size_t header_size = HeaderSize(component_size);
54  size_t data_size = component_count * component_size;
55  size_t size = header_size + data_size;
56
57  // Check for overflow and throw OutOfMemoryError if this was an unreasonable request.
58  size_t component_shift = sizeof(size_t) * 8 - 1 - CLZ(component_size);
59  if (UNLIKELY(data_size >> component_shift != size_t(component_count) || size < data_size)) {
60    self->ThrowOutOfMemoryError(StringPrintf("%s of length %d would overflow",
61                                             PrettyDescriptor(array_class).c_str(),
62                                             component_count).c_str());
63    return 0;  // failure
64  }
65  return size;
66}
67
68// Used for setting the array length in the allocation code path to ensure it is guarded by a
69// StoreStore fence.
70class SetLengthVisitor {
71 public:
72  explicit SetLengthVisitor(int32_t length) : length_(length) {
73  }
74
75  void operator()(Object* obj, size_t usable_size) const
76      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
77    UNUSED(usable_size);
78    // Avoid AsArray as object is not yet in live bitmap or allocation stack.
79    Array* array = down_cast<Array*>(obj);
80    // DCHECK(array->IsArrayInstance());
81    array->SetLength(length_);
82  }
83
84 private:
85  const int32_t length_;
86
87  DISALLOW_COPY_AND_ASSIGN(SetLengthVisitor);
88};
89
90// Similar to SetLengthVisitor, used for setting the array length to fill the usable size of an
91// array.
92class SetLengthToUsableSizeVisitor {
93 public:
94  SetLengthToUsableSizeVisitor(int32_t min_length, size_t header_size, size_t component_size) :
95      minimum_length_(min_length), header_size_(header_size), component_size_(component_size) {
96  }
97
98  void operator()(Object* obj, size_t usable_size) const
99      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
100    // Avoid AsArray as object is not yet in live bitmap or allocation stack.
101    Array* array = down_cast<Array*>(obj);
102    // DCHECK(array->IsArrayInstance());
103    int32_t length = (usable_size - header_size_) / component_size_;
104    DCHECK_GE(length, minimum_length_);
105    byte* old_end = reinterpret_cast<byte*>(array->GetRawData(component_size_, minimum_length_));
106    byte* new_end = reinterpret_cast<byte*>(array->GetRawData(component_size_, length));
107    // Ensure space beyond original allocation is zeroed.
108    memset(old_end, 0, new_end - old_end);
109    array->SetLength(length);
110  }
111
112 private:
113  const int32_t minimum_length_;
114  const size_t header_size_;
115  const size_t component_size_;
116
117  DISALLOW_COPY_AND_ASSIGN(SetLengthToUsableSizeVisitor);
118};
119
120template <bool kIsInstrumented>
121inline Array* Array::Alloc(Thread* self, Class* array_class, int32_t component_count,
122                           size_t component_size, gc::AllocatorType allocator_type,
123                           bool fill_usable) {
124  DCHECK(allocator_type != gc::kAllocatorTypeLOS);
125  size_t size = ComputeArraySize(self, array_class, component_count, component_size);
126  if (UNLIKELY(size == 0)) {
127    return nullptr;
128  }
129  gc::Heap* heap = Runtime::Current()->GetHeap();
130  Array* result;
131  if (!fill_usable) {
132    SetLengthVisitor visitor(component_count);
133    result = down_cast<Array*>(
134        heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size,
135                                                              allocator_type, visitor));
136  } else {
137    SetLengthToUsableSizeVisitor visitor(component_count, HeaderSize(component_size),
138                                         component_size);
139    result = down_cast<Array*>(
140        heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size,
141                                                              allocator_type, visitor));
142  }
143  if (kIsDebugBuild && result != nullptr && Runtime::Current()->IsStarted()) {
144    CHECK_EQ(array_class->GetComponentSize(), component_size);
145    if (!fill_usable) {
146      CHECK_EQ(result->SizeOf(), size);
147    } else {
148      CHECK_GE(result->SizeOf(), size);
149    }
150  }
151  return result;
152}
153
154template<class T>
155inline void PrimitiveArray<T>::VisitRoots(RootCallback* callback, void* arg) {
156  if (array_class_ != nullptr) {
157    callback(reinterpret_cast<mirror::Object**>(&array_class_), arg, 0, kRootStickyClass);
158  }
159}
160
161// Similar to memmove except elements are of aligned appropriately for T, count is in T sized units
162// copies are guaranteed not to tear when T is less-than 64bit.
163template<typename T>
164static inline void ArrayBackwardCopy(T* d, const T* s, int32_t count) {
165  d += count;
166  s += count;
167  for (int32_t i = 0; i < count; ++i) {
168    d--;
169    s--;
170    *d = *s;
171  }
172}
173
174template<typename T>
175inline PrimitiveArray<T>* PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
176  DCHECK(array_class_ != NULL);
177  Array* raw_array = Array::Alloc<true>(self, array_class_, length, sizeof(T),
178                                        Runtime::Current()->GetHeap()->GetCurrentAllocator());
179  return down_cast<PrimitiveArray<T>*>(raw_array);
180}
181
182template<class T>
183inline void PrimitiveArray<T>::Memmove(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos,
184                                       int32_t count) {
185  if (UNLIKELY(count == 0)) {
186    return;
187  }
188  DCHECK_GE(dst_pos, 0);
189  DCHECK_GE(src_pos, 0);
190  DCHECK_GT(count, 0);
191  DCHECK(src != nullptr);
192  DCHECK_LT(dst_pos, GetLength());
193  DCHECK_LE(dst_pos, GetLength() - count);
194  DCHECK_LT(src_pos, src->GetLength());
195  DCHECK_LE(src_pos, src->GetLength() - count);
196
197  // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3)
198  // in our implementation, because they may copy byte-by-byte.
199  if (LIKELY(src != this) || (dst_pos < src_pos) || (dst_pos - src_pos >= count)) {
200    // Forward copy ok.
201    Memcpy(dst_pos, src, src_pos, count);
202  } else {
203    // Backward copy necessary.
204    void* dst_raw = GetRawData(sizeof(T), dst_pos);
205    const void* src_raw = src->GetRawData(sizeof(T), src_pos);
206    if (sizeof(T) == sizeof(uint8_t)) {
207      // TUNING: use memmove here?
208      uint8_t* d = reinterpret_cast<uint8_t*>(dst_raw);
209      const uint8_t* s = reinterpret_cast<const uint8_t*>(src_raw);
210      ArrayBackwardCopy<uint8_t>(d, s, count);
211    } else if (sizeof(T) == sizeof(uint16_t)) {
212      uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw);
213      const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw);
214      ArrayBackwardCopy<uint16_t>(d, s, count);
215    } else if (sizeof(T) == sizeof(uint32_t)) {
216      uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw);
217      const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw);
218      ArrayBackwardCopy<uint32_t>(d, s, count);
219    } else {
220      DCHECK_EQ(sizeof(T), sizeof(uint64_t));
221      uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw);
222      const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw);
223      ArrayBackwardCopy<uint64_t>(d, s, count);
224    }
225  }
226}
227
228// Similar to memcpy except elements are of aligned appropriately for T, count is in T sized units
229// copies are guaranteed not to tear when T is less-than 64bit.
230template<typename T>
231static inline void ArrayForwardCopy(T* d, const T* s, int32_t count) {
232  for (int32_t i = 0; i < count; ++i) {
233    *d = *s;
234    d++;
235    s++;
236  }
237}
238
239
240template<class T>
241inline void PrimitiveArray<T>::Memcpy(int32_t dst_pos, PrimitiveArray<T>* src, int32_t src_pos,
242                                      int32_t count) {
243  if (UNLIKELY(count == 0)) {
244    return;
245  }
246  DCHECK_GE(dst_pos, 0);
247  DCHECK_GE(src_pos, 0);
248  DCHECK_GT(count, 0);
249  DCHECK(src != nullptr);
250  DCHECK_LT(dst_pos, GetLength());
251  DCHECK_LE(dst_pos, GetLength() - count);
252  DCHECK_LT(src_pos, src->GetLength());
253  DCHECK_LE(src_pos, src->GetLength() - count);
254
255  // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3)
256  // in our implementation, because they may copy byte-by-byte.
257  void* dst_raw = GetRawData(sizeof(T), dst_pos);
258  const void* src_raw = src->GetRawData(sizeof(T), src_pos);
259  if (sizeof(T) == sizeof(uint8_t)) {
260    memcpy(dst_raw, src_raw, count);
261  } else if (sizeof(T) == sizeof(uint16_t)) {
262    uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw);
263    const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw);
264    ArrayForwardCopy<uint16_t>(d, s, count);
265  } else if (sizeof(T) == sizeof(uint32_t)) {
266    uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw);
267    const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw);
268    ArrayForwardCopy<uint32_t>(d, s, count);
269  } else {
270    DCHECK_EQ(sizeof(T), sizeof(uint64_t));
271    uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw);
272    const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw);
273    ArrayForwardCopy<uint64_t>(d, s, count);
274  }
275}
276
277}  // namespace mirror
278}  // namespace art
279
280#endif  // ART_RUNTIME_MIRROR_ARRAY_INL_H_
281