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_ALLOC_INL_H_
18 #define ART_RUNTIME_MIRROR_ARRAY_ALLOC_INL_H_
19
20 #include "array-inl.h"
21
22 #include <android-base/logging.h>
23 #include <android-base/stringprintf.h>
24
25 #include "base/bit_utils.h"
26 #include "base/casts.h"
27 #include "class.h"
28 #include "gc/allocator_type.h"
29 #include "gc/heap-inl.h"
30 #include "obj_ptr-inl.h"
31 #include "runtime.h"
32
33 namespace art {
34 namespace mirror {
35
ComputeArraySize(int32_t component_count,size_t component_size_shift)36 static inline size_t ComputeArraySize(int32_t component_count, size_t component_size_shift) {
37 DCHECK_GE(component_count, 0);
38
39 size_t component_size = 1U << component_size_shift;
40 size_t header_size = Array::DataOffset(component_size).SizeValue();
41 size_t data_size = static_cast<size_t>(component_count) << component_size_shift;
42 size_t size = header_size + data_size;
43
44 // Check for size_t overflow if this was an unreasonable request
45 // but let the caller throw OutOfMemoryError.
46 #ifdef __LP64__
47 // 64-bit. No overflow as component_count is 32-bit and the maximum
48 // component size is 8.
49 DCHECK_LE((1U << component_size_shift), 8U);
50 #else
51 // 32-bit.
52 DCHECK_NE(header_size, 0U);
53 DCHECK_EQ(RoundUp(header_size, component_size), header_size);
54 // The array length limit (exclusive).
55 const size_t length_limit = (0U - header_size) >> component_size_shift;
56 if (UNLIKELY(length_limit <= static_cast<size_t>(component_count))) {
57 return 0; // failure
58 }
59 #endif
60 return size;
61 }
62
63 // Used for setting the array length in the allocation code path to ensure it is guarded by a
64 // StoreStore fence.
65 class SetLengthVisitor {
66 public:
SetLengthVisitor(int32_t length)67 explicit SetLengthVisitor(int32_t length) : length_(length) {
68 }
69
operator()70 void operator()(ObjPtr<Object> obj, size_t usable_size ATTRIBUTE_UNUSED) const
71 REQUIRES_SHARED(Locks::mutator_lock_) {
72 // Avoid AsArray as object is not yet in live bitmap or allocation stack.
73 ObjPtr<Array> array = ObjPtr<Array>::DownCast(obj);
74 // DCHECK(array->IsArrayInstance());
75 array->SetLength(length_);
76 }
77
78 private:
79 const int32_t length_;
80
81 DISALLOW_COPY_AND_ASSIGN(SetLengthVisitor);
82 };
83
84 // Similar to SetLengthVisitor, used for setting the array length to fill the usable size of an
85 // array.
86 class SetLengthToUsableSizeVisitor {
87 public:
SetLengthToUsableSizeVisitor(int32_t min_length,size_t header_size,size_t component_size_shift)88 SetLengthToUsableSizeVisitor(int32_t min_length, size_t header_size,
89 size_t component_size_shift) :
90 minimum_length_(min_length), header_size_(header_size),
91 component_size_shift_(component_size_shift) {
92 }
93
operator()94 void operator()(ObjPtr<Object> obj, size_t usable_size) const
95 REQUIRES_SHARED(Locks::mutator_lock_) {
96 // Avoid AsArray as object is not yet in live bitmap or allocation stack.
97 ObjPtr<Array> array = ObjPtr<Array>::DownCast(obj);
98 // DCHECK(array->IsArrayInstance());
99 int32_t length = (usable_size - header_size_) >> component_size_shift_;
100 DCHECK_GE(length, minimum_length_);
101 uint8_t* old_end = reinterpret_cast<uint8_t*>(array->GetRawData(1U << component_size_shift_,
102 minimum_length_));
103 uint8_t* new_end = reinterpret_cast<uint8_t*>(array->GetRawData(1U << component_size_shift_,
104 length));
105 // Ensure space beyond original allocation is zeroed.
106 memset(old_end, 0, new_end - old_end);
107 array->SetLength(length);
108 }
109
110 private:
111 const int32_t minimum_length_;
112 const size_t header_size_;
113 const size_t component_size_shift_;
114
115 DISALLOW_COPY_AND_ASSIGN(SetLengthToUsableSizeVisitor);
116 };
117
118 template <bool kIsInstrumented, bool kFillUsable>
Alloc(Thread * self,ObjPtr<Class> array_class,int32_t component_count,size_t component_size_shift,gc::AllocatorType allocator_type)119 inline ObjPtr<Array> Array::Alloc(Thread* self,
120 ObjPtr<Class> array_class,
121 int32_t component_count,
122 size_t component_size_shift,
123 gc::AllocatorType allocator_type) {
124 DCHECK(allocator_type != gc::kAllocatorTypeLOS);
125 DCHECK(array_class != nullptr);
126 DCHECK(array_class->IsArrayClass());
127 DCHECK_EQ(array_class->GetComponentSizeShift(), component_size_shift);
128 DCHECK_EQ(array_class->GetComponentSize(), (1U << component_size_shift));
129 size_t size = ComputeArraySize(component_count, component_size_shift);
130 #ifdef __LP64__
131 // 64-bit. No size_t overflow.
132 DCHECK_NE(size, 0U);
133 #else
134 // 32-bit.
135 if (UNLIKELY(size == 0)) {
136 self->ThrowOutOfMemoryError(android::base::StringPrintf("%s of length %d would overflow",
137 array_class->PrettyDescriptor().c_str(),
138 component_count).c_str());
139 return nullptr;
140 }
141 #endif
142 gc::Heap* heap = Runtime::Current()->GetHeap();
143 ObjPtr<Array> result;
144 if (!kFillUsable) {
145 SetLengthVisitor visitor(component_count);
146 result = ObjPtr<Array>::DownCast(
147 heap->AllocObjectWithAllocator<kIsInstrumented>(
148 self, array_class, size, allocator_type, visitor));
149 } else {
150 SetLengthToUsableSizeVisitor visitor(component_count,
151 DataOffset(1U << component_size_shift).SizeValue(),
152 component_size_shift);
153 result = ObjPtr<Array>::DownCast(
154 heap->AllocObjectWithAllocator<kIsInstrumented>(
155 self, array_class, size, allocator_type, visitor));
156 }
157 if (kIsDebugBuild && result != nullptr && Runtime::Current()->IsStarted()) {
158 array_class = result->GetClass(); // In case the array class moved.
159 CHECK_EQ(array_class->GetComponentSize(), 1U << component_size_shift);
160 if (!kFillUsable) {
161 CHECK_EQ(result->SizeOf(), size);
162 } else {
163 CHECK_GE(result->SizeOf(), size);
164 }
165 }
166 return result;
167 }
168
169 template<typename T>
AllocateAndFill(Thread * self,const T * data,size_t length)170 inline ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::AllocateAndFill(Thread* self,
171 const T* data,
172 size_t length) {
173 StackHandleScope<1> hs(self);
174 Handle<PrimitiveArray<T>> arr(hs.NewHandle(PrimitiveArray<T>::Alloc(self, length)));
175 if (!arr.IsNull()) {
176 // Copy it in. Just skip if it's null
177 memcpy(arr->GetData(), data, sizeof(T) * length);
178 }
179 return arr.Get();
180 }
181
182 } // namespace mirror
183 } // namespace art
184
185 #endif // ART_RUNTIME_MIRROR_ARRAY_ALLOC_INL_H_
186