Home | History | Annotate | Download | only in mirror
      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 "class.h"
     20 #include "class-inl.h"
     21 #include "class_linker-inl.h"
     22 #include "common_throws.h"
     23 #include "dex_file-inl.h"
     24 #include "gc/accounting/card_table-inl.h"
     25 #include "object-inl.h"
     26 #include "object_array-inl.h"
     27 #include "handle_scope-inl.h"
     28 #include "thread.h"
     29 #include "utils.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