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