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 #include "array-inl.h" 18 19 #include "base/utils.h" 20 #include "class-inl.h" 21 #include "class.h" 22 #include "class_linker-inl.h" 23 #include "common_throws.h" 24 #include "dex/dex_file-inl.h" 25 #include "gc/accounting/card_table-inl.h" 26 #include "handle_scope-inl.h" 27 #include "object-inl.h" 28 #include "object_array-inl.h" 29 #include "thread.h" 30 31 namespace art { 32 namespace mirror { 33 34 using android::base::StringPrintf; 35 36 // Create a multi-dimensional array of Objects or primitive types. 37 // 38 // We have to generate the names for X[], X[][], X[][][], and so on. The 39 // easiest way to deal with that is to create the full name once and then 40 // subtract pieces off. Besides, we want to start with the outermost 41 // piece and work our way in. 42 // Recursively create an array with multiple dimensions. Elements may be 43 // Objects or primitive types. 44 static Array* RecursiveCreateMultiArray(Thread* self, 45 Handle<Class> array_class, int current_dimension, 46 Handle<mirror::IntArray> dimensions) 47 REQUIRES_SHARED(Locks::mutator_lock_) { 48 int32_t array_length = dimensions->Get(current_dimension); 49 StackHandleScope<1> hs(self); 50 Handle<Array> new_array( 51 hs.NewHandle( 52 Array::Alloc<true>(self, array_class.Get(), array_length, 53 array_class->GetComponentSizeShift(), 54 Runtime::Current()->GetHeap()->GetCurrentAllocator()))); 55 if (UNLIKELY(new_array == nullptr)) { 56 CHECK(self->IsExceptionPending()); 57 return nullptr; 58 } 59 if (current_dimension + 1 < dimensions->GetLength()) { 60 // Create a new sub-array in every element of the array. 61 for (int32_t i = 0; i < array_length; i++) { 62 StackHandleScope<1> hs2(self); 63 Handle<mirror::Class> h_component_type(hs2.NewHandle(array_class->GetComponentType())); 64 ObjPtr<Array> sub_array = RecursiveCreateMultiArray(self, h_component_type, 65 current_dimension + 1, dimensions); 66 if (UNLIKELY(sub_array == nullptr)) { 67 CHECK(self->IsExceptionPending()); 68 return nullptr; 69 } 70 // Use non-transactional mode without check. 71 new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array); 72 } 73 } 74 return new_array.Get(); 75 } 76 77 Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, 78 Handle<IntArray> dimensions) { 79 // Verify dimensions. 80 // 81 // The caller is responsible for verifying that "dimArray" is non-null 82 // and has a length > 0 and <= 255. 83 int num_dimensions = dimensions->GetLength(); 84 DCHECK_GT(num_dimensions, 0); 85 DCHECK_LE(num_dimensions, 255); 86 87 for (int i = 0; i < num_dimensions; i++) { 88 int dimension = dimensions->Get(i); 89 if (UNLIKELY(dimension < 0)) { 90 ThrowNegativeArraySizeException(StringPrintf("Dimension %d: %d", i, dimension).c_str()); 91 return nullptr; 92 } 93 } 94 95 // Find/generate the array class. 96 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 97 ObjPtr<mirror::Class> element_class_ptr = element_class.Get(); 98 StackHandleScope<1> hs(self); 99 MutableHandle<mirror::Class> array_class( 100 hs.NewHandle(class_linker->FindArrayClass(self, &element_class_ptr))); 101 if (UNLIKELY(array_class == nullptr)) { 102 CHECK(self->IsExceptionPending()); 103 return nullptr; 104 } 105 for (int32_t i = 1; i < dimensions->GetLength(); ++i) { 106 ObjPtr<mirror::Class> array_class_ptr = array_class.Get(); 107 array_class.Assign(class_linker->FindArrayClass(self, &array_class_ptr)); 108 if (UNLIKELY(array_class == nullptr)) { 109 CHECK(self->IsExceptionPending()); 110 return nullptr; 111 } 112 } 113 // Create the array. 114 ObjPtr<Array> new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions); 115 if (UNLIKELY(new_array == nullptr)) { 116 CHECK(self->IsExceptionPending()); 117 } 118 return new_array.Ptr(); 119 } 120 121 void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) { 122 art::ThrowArrayIndexOutOfBoundsException(index, GetLength()); 123 } 124 125 void Array::ThrowArrayStoreException(ObjPtr<Object> object) { 126 art::ThrowArrayStoreException(object->GetClass(), this->GetClass()); 127 } 128 129 Array* Array::CopyOf(Thread* self, int32_t new_length) { 130 CHECK(GetClass()->GetComponentType()->IsPrimitive()) << "Will miss write barriers"; 131 DCHECK_GE(new_length, 0); 132 // We may get copied by a compacting GC. 133 StackHandleScope<1> hs(self); 134 auto h_this(hs.NewHandle(this)); 135 auto* heap = Runtime::Current()->GetHeap(); 136 gc::AllocatorType allocator_type = heap->IsMovableObject(this) ? heap->GetCurrentAllocator() : 137 heap->GetCurrentNonMovingAllocator(); 138 const auto component_size = GetClass()->GetComponentSize(); 139 const auto component_shift = GetClass()->GetComponentSizeShift(); 140 ObjPtr<Array> new_array = Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type); 141 if (LIKELY(new_array != nullptr)) { 142 memcpy(new_array->GetRawData(component_size, 0), 143 h_this->GetRawData(component_size, 0), 144 std::min(h_this->GetLength(), new_length) << component_shift); 145 } 146 return new_array.Ptr(); 147 } 148 149 150 template <typename T> GcRoot<Class> PrimitiveArray<T>::array_class_; 151 152 // Explicitly instantiate all the primitive array types. 153 template class PrimitiveArray<uint8_t>; // BooleanArray 154 template class PrimitiveArray<int8_t>; // ByteArray 155 template class PrimitiveArray<uint16_t>; // CharArray 156 template class PrimitiveArray<double>; // DoubleArray 157 template class PrimitiveArray<float>; // FloatArray 158 template class PrimitiveArray<int32_t>; // IntArray 159 template class PrimitiveArray<int64_t>; // LongArray 160 template class PrimitiveArray<int16_t>; // ShortArray 161 162 } // namespace mirror 163 } // namespace art 164