174 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2011 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #include "array-inl.h"
 | |
| 
 | |
| #include "array-alloc-inl.h"
 | |
| #include "base/utils.h"
 | |
| #include "class-inl.h"
 | |
| #include "class.h"
 | |
| #include "class_linker-inl.h"
 | |
| #include "class_root-inl.h"
 | |
| #include "common_throws.h"
 | |
| #include "dex/dex_file-inl.h"
 | |
| #include "gc/accounting/card_table-inl.h"
 | |
| #include "handle_scope-inl.h"
 | |
| #include "object-inl.h"
 | |
| #include "object_array-alloc-inl.h"
 | |
| #include "object_array-inl.h"
 | |
| #include "thread.h"
 | |
| 
 | |
| namespace art {
 | |
| namespace mirror {
 | |
| 
 | |
| using android::base::StringPrintf;
 | |
| 
 | |
| // Create a multi-dimensional array of Objects or primitive types.
 | |
| //
 | |
| // We have to generate the names for X[], X[][], X[][][], and so on.  The
 | |
| // easiest way to deal with that is to create the full name once and then
 | |
| // subtract pieces off.  Besides, we want to start with the outermost
 | |
| // piece and work our way in.
 | |
| // Recursively create an array with multiple dimensions.  Elements may be
 | |
| // Objects or primitive types.
 | |
| static ObjPtr<Array> RecursiveCreateMultiArray(Thread* self,
 | |
|                                                Handle<Class> array_class,
 | |
|                                                int current_dimension,
 | |
|                                                Handle<mirror::IntArray> dimensions)
 | |
|     REQUIRES_SHARED(Locks::mutator_lock_) {
 | |
|   int32_t array_length = dimensions->Get(current_dimension);
 | |
|   StackHandleScope<2> hs(self);
 | |
|   Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType()));
 | |
|   size_t component_size_shift = h_component_type->GetPrimitiveTypeSizeShift();
 | |
|   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
 | |
|   Handle<Array> new_array(hs.NewHandle(
 | |
|       Array::Alloc(self, array_class.Get(), array_length, component_size_shift, allocator_type)));
 | |
|   if (UNLIKELY(new_array == nullptr)) {
 | |
|     CHECK(self->IsExceptionPending());
 | |
|     return nullptr;
 | |
|   }
 | |
|   if (current_dimension + 1 < dimensions->GetLength()) {
 | |
|     // Create a new sub-array in every element of the array.
 | |
|     for (int32_t i = 0; i < array_length; i++) {
 | |
|       ObjPtr<Array> sub_array =
 | |
|           RecursiveCreateMultiArray(self, h_component_type, current_dimension + 1, dimensions);
 | |
|       if (UNLIKELY(sub_array == nullptr)) {
 | |
|         CHECK(self->IsExceptionPending());
 | |
|         return nullptr;
 | |
|       }
 | |
|       // Use non-transactional mode without check.
 | |
|       new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array);
 | |
|     }
 | |
|   }
 | |
|   return new_array.Get();
 | |
| }
 | |
| 
 | |
| ObjPtr<Array> Array::CreateMultiArray(Thread* self,
 | |
|                                       Handle<Class> element_class,
 | |
|                                       Handle<IntArray> dimensions) {
 | |
|   // Verify dimensions.
 | |
|   //
 | |
|   // The caller is responsible for verifying that "dimArray" is non-null
 | |
|   // and has a length > 0 and <= 255.
 | |
|   int num_dimensions = dimensions->GetLength();
 | |
|   DCHECK_GT(num_dimensions, 0);
 | |
|   DCHECK_LE(num_dimensions, 255);
 | |
| 
 | |
|   for (int i = 0; i < num_dimensions; i++) {
 | |
|     int dimension = dimensions->Get(i);
 | |
|     if (UNLIKELY(dimension < 0)) {
 | |
|       ThrowNegativeArraySizeException(StringPrintf("Dimension %d: %d", i, dimension).c_str());
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Find/generate the array class.
 | |
|   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 | |
|   StackHandleScope<1> hs(self);
 | |
|   MutableHandle<mirror::Class> array_class(
 | |
|       hs.NewHandle(class_linker->FindArrayClass(self, element_class.Get())));
 | |
|   if (UNLIKELY(array_class == nullptr)) {
 | |
|     CHECK(self->IsExceptionPending());
 | |
|     return nullptr;
 | |
|   }
 | |
|   for (int32_t i = 1; i < dimensions->GetLength(); ++i) {
 | |
|     array_class.Assign(class_linker->FindArrayClass(self, array_class.Get()));
 | |
|     if (UNLIKELY(array_class == nullptr)) {
 | |
|       CHECK(self->IsExceptionPending());
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
|   // Create the array.
 | |
|   ObjPtr<Array> new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions);
 | |
|   if (UNLIKELY(new_array == nullptr)) {
 | |
|     CHECK(self->IsExceptionPending());
 | |
|   }
 | |
|   return new_array.Ptr();
 | |
| }
 | |
| 
 | |
| template<typename T>
 | |
| ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
 | |
|   Runtime* runtime = Runtime::Current();
 | |
|   gc::AllocatorType allocator_type = runtime->GetHeap()->GetCurrentAllocator();
 | |
|   ObjPtr<Array> raw_array = Array::Alloc(self,
 | |
|                                          GetClassRoot<PrimitiveArray<T>>(runtime->GetClassLinker()),
 | |
|                                          length,
 | |
|                                          ComponentSizeShiftWidth(sizeof(T)),
 | |
|                                          allocator_type);
 | |
|   return ObjPtr<PrimitiveArray<T>>::DownCast(raw_array);
 | |
| }
 | |
| 
 | |
| void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) {
 | |
|   art::ThrowArrayIndexOutOfBoundsException(index, GetLength());
 | |
| }
 | |
| 
 | |
| void Array::ThrowArrayStoreException(ObjPtr<Object> object) {
 | |
|   art::ThrowArrayStoreException(object->GetClass(), this->GetClass());
 | |
| }
 | |
| 
 | |
| ObjPtr<Array> Array::CopyOf(Handle<Array> h_this, Thread* self, int32_t new_length) {
 | |
|   ObjPtr<Class> klass = h_this->GetClass();
 | |
|   CHECK(klass->IsPrimitiveArray()) << "Will miss write barriers";
 | |
|   DCHECK_GE(new_length, 0);
 | |
|   auto* heap = Runtime::Current()->GetHeap();
 | |
|   gc::AllocatorType allocator_type = heap->IsMovableObject(h_this.Get())
 | |
|       ? heap->GetCurrentAllocator()
 | |
|       : heap->GetCurrentNonMovingAllocator();
 | |
|   const auto component_size = klass->GetComponentSize();
 | |
|   const auto component_shift = klass->GetComponentSizeShift();
 | |
|   ObjPtr<Array> new_array =
 | |
|       Alloc(self, klass, new_length, component_shift, allocator_type);  // Invalidates klass.
 | |
|   if (LIKELY(new_array != nullptr)) {
 | |
|     memcpy(new_array->GetRawData(component_size, 0),
 | |
|            h_this->GetRawData(component_size, 0),
 | |
|            std::min(h_this->GetLength(), new_length) << component_shift);
 | |
|   }
 | |
|   return new_array;
 | |
| }
 | |
| 
 | |
| // Explicitly instantiate all the primitive array types.
 | |
| template class PrimitiveArray<uint8_t>;   // BooleanArray
 | |
| template class PrimitiveArray<int8_t>;    // ByteArray
 | |
| template class PrimitiveArray<uint16_t>;  // CharArray
 | |
| template class PrimitiveArray<double>;    // DoubleArray
 | |
| template class PrimitiveArray<float>;     // FloatArray
 | |
| template class PrimitiveArray<int32_t>;   // IntArray
 | |
| template class PrimitiveArray<int64_t>;   // LongArray
 | |
| template class PrimitiveArray<int16_t>;   // ShortArray
 | |
| 
 | |
| }  // namespace mirror
 | |
| }  // namespace art
 |