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 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: 67 explicit SetLengthVisitor(int32_t length) : length_(length) { 68 } 69 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: 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 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> 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> 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