xref: /aosp_15_r20/art/runtime/mirror/array.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "array-inl.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "array-alloc-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
21*795d594fSAndroid Build Coastguard Worker #include "class-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "class.h"
23*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "common_throws.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/card_table-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "object-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "object_array-alloc-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "object_array-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "thread.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker namespace mirror {
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker // Create a multi-dimensional array of Objects or primitive types.
40*795d594fSAndroid Build Coastguard Worker //
41*795d594fSAndroid Build Coastguard Worker // We have to generate the names for X[], X[][], X[][][], and so on.  The
42*795d594fSAndroid Build Coastguard Worker // easiest way to deal with that is to create the full name once and then
43*795d594fSAndroid Build Coastguard Worker // subtract pieces off.  Besides, we want to start with the outermost
44*795d594fSAndroid Build Coastguard Worker // piece and work our way in.
45*795d594fSAndroid Build Coastguard Worker // Recursively create an array with multiple dimensions.  Elements may be
46*795d594fSAndroid Build Coastguard Worker // Objects or primitive types.
RecursiveCreateMultiArray(Thread * self,Handle<Class> array_class,int current_dimension,Handle<mirror::IntArray> dimensions)47*795d594fSAndroid Build Coastguard Worker static ObjPtr<Array> RecursiveCreateMultiArray(Thread* self,
48*795d594fSAndroid Build Coastguard Worker                                                Handle<Class> array_class,
49*795d594fSAndroid Build Coastguard Worker                                                int current_dimension,
50*795d594fSAndroid Build Coastguard Worker                                                Handle<mirror::IntArray> dimensions)
51*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
52*795d594fSAndroid Build Coastguard Worker   int32_t array_length = dimensions->Get(current_dimension);
53*795d594fSAndroid Build Coastguard Worker   StackHandleScope<2> hs(self);
54*795d594fSAndroid Build Coastguard Worker   Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType()));
55*795d594fSAndroid Build Coastguard Worker   size_t component_size_shift = h_component_type->GetPrimitiveTypeSizeShift();
56*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
57*795d594fSAndroid Build Coastguard Worker   Handle<Array> new_array(hs.NewHandle(
58*795d594fSAndroid Build Coastguard Worker       Array::Alloc(self, array_class.Get(), array_length, component_size_shift, allocator_type)));
59*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(new_array == nullptr)) {
60*795d594fSAndroid Build Coastguard Worker     CHECK(self->IsExceptionPending());
61*795d594fSAndroid Build Coastguard Worker     return nullptr;
62*795d594fSAndroid Build Coastguard Worker   }
63*795d594fSAndroid Build Coastguard Worker   if (current_dimension + 1 < dimensions->GetLength()) {
64*795d594fSAndroid Build Coastguard Worker     // Create a new sub-array in every element of the array.
65*795d594fSAndroid Build Coastguard Worker     for (int32_t i = 0; i < array_length; i++) {
66*795d594fSAndroid Build Coastguard Worker       ObjPtr<Array> sub_array =
67*795d594fSAndroid Build Coastguard Worker           RecursiveCreateMultiArray(self, h_component_type, current_dimension + 1, dimensions);
68*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(sub_array == nullptr)) {
69*795d594fSAndroid Build Coastguard Worker         CHECK(self->IsExceptionPending());
70*795d594fSAndroid Build Coastguard Worker         return nullptr;
71*795d594fSAndroid Build Coastguard Worker       }
72*795d594fSAndroid Build Coastguard Worker       // Use non-transactional mode without check.
73*795d594fSAndroid Build Coastguard Worker       new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array);
74*795d594fSAndroid Build Coastguard Worker     }
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker   return new_array.Get();
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker 
CreateMultiArray(Thread * self,Handle<Class> element_class,Handle<IntArray> dimensions)79*795d594fSAndroid Build Coastguard Worker ObjPtr<Array> Array::CreateMultiArray(Thread* self,
80*795d594fSAndroid Build Coastguard Worker                                       Handle<Class> element_class,
81*795d594fSAndroid Build Coastguard Worker                                       Handle<IntArray> dimensions) {
82*795d594fSAndroid Build Coastguard Worker   // Verify dimensions.
83*795d594fSAndroid Build Coastguard Worker   //
84*795d594fSAndroid Build Coastguard Worker   // The caller is responsible for verifying that "dimArray" is non-null
85*795d594fSAndroid Build Coastguard Worker   // and has a length > 0 and <= 255.
86*795d594fSAndroid Build Coastguard Worker   int num_dimensions = dimensions->GetLength();
87*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(num_dimensions, 0);
88*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(num_dimensions, 255);
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker   for (int i = 0; i < num_dimensions; i++) {
91*795d594fSAndroid Build Coastguard Worker     int dimension = dimensions->Get(i);
92*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(dimension < 0)) {
93*795d594fSAndroid Build Coastguard Worker       ThrowNegativeArraySizeException(StringPrintf("Dimension %d: %d", i, dimension).c_str());
94*795d594fSAndroid Build Coastguard Worker       return nullptr;
95*795d594fSAndroid Build Coastguard Worker     }
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker   // Find/generate the array class.
99*795d594fSAndroid Build Coastguard Worker   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
100*795d594fSAndroid Build Coastguard Worker   StackHandleScope<1> hs(self);
101*795d594fSAndroid Build Coastguard Worker   MutableHandle<mirror::Class> array_class(
102*795d594fSAndroid Build Coastguard Worker       hs.NewHandle(class_linker->FindArrayClass(self, element_class.Get())));
103*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(array_class == nullptr)) {
104*795d594fSAndroid Build Coastguard Worker     CHECK(self->IsExceptionPending());
105*795d594fSAndroid Build Coastguard Worker     return nullptr;
106*795d594fSAndroid Build Coastguard Worker   }
107*795d594fSAndroid Build Coastguard Worker   for (int32_t i = 1; i < dimensions->GetLength(); ++i) {
108*795d594fSAndroid Build Coastguard Worker     array_class.Assign(class_linker->FindArrayClass(self, array_class.Get()));
109*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(array_class == nullptr)) {
110*795d594fSAndroid Build Coastguard Worker       CHECK(self->IsExceptionPending());
111*795d594fSAndroid Build Coastguard Worker       return nullptr;
112*795d594fSAndroid Build Coastguard Worker     }
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker   // Create the array.
115*795d594fSAndroid Build Coastguard Worker   ObjPtr<Array> new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions);
116*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(new_array == nullptr)) {
117*795d594fSAndroid Build Coastguard Worker     CHECK(self->IsExceptionPending());
118*795d594fSAndroid Build Coastguard Worker   }
119*795d594fSAndroid Build Coastguard Worker   return new_array.Ptr();
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker template<typename T>
Alloc(Thread * self,size_t length)123*795d594fSAndroid Build Coastguard Worker ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
124*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
125*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = runtime->GetHeap()->GetCurrentAllocator();
126*795d594fSAndroid Build Coastguard Worker   ObjPtr<Array> raw_array = Array::Alloc(self,
127*795d594fSAndroid Build Coastguard Worker                                          GetClassRoot<PrimitiveArray<T>>(runtime->GetClassLinker()),
128*795d594fSAndroid Build Coastguard Worker                                          length,
129*795d594fSAndroid Build Coastguard Worker                                          ComponentSizeShiftWidth(sizeof(T)),
130*795d594fSAndroid Build Coastguard Worker                                          allocator_type);
131*795d594fSAndroid Build Coastguard Worker   return ObjPtr<PrimitiveArray<T>>::DownCast(raw_array);
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker 
ThrowArrayIndexOutOfBoundsException(int32_t index)134*795d594fSAndroid Build Coastguard Worker void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) {
135*795d594fSAndroid Build Coastguard Worker   art::ThrowArrayIndexOutOfBoundsException(index, GetLength());
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker 
ThrowArrayStoreException(ObjPtr<Object> object)138*795d594fSAndroid Build Coastguard Worker void Array::ThrowArrayStoreException(ObjPtr<Object> object) {
139*795d594fSAndroid Build Coastguard Worker   art::ThrowArrayStoreException(object->GetClass(), this->GetClass());
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker 
CopyOf(Handle<Array> h_this,Thread * self,int32_t new_length)142*795d594fSAndroid Build Coastguard Worker ObjPtr<Array> Array::CopyOf(Handle<Array> h_this, Thread* self, int32_t new_length) {
143*795d594fSAndroid Build Coastguard Worker   ObjPtr<Class> klass = h_this->GetClass();
144*795d594fSAndroid Build Coastguard Worker   CHECK(klass->IsPrimitiveArray()) << "Will miss write barriers";
145*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(new_length, 0);
146*795d594fSAndroid Build Coastguard Worker   auto* heap = Runtime::Current()->GetHeap();
147*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = heap->IsMovableObject(h_this.Get())
148*795d594fSAndroid Build Coastguard Worker       ? heap->GetCurrentAllocator()
149*795d594fSAndroid Build Coastguard Worker       : heap->GetCurrentNonMovingAllocator();
150*795d594fSAndroid Build Coastguard Worker   const auto component_size = klass->GetComponentSize();
151*795d594fSAndroid Build Coastguard Worker   const auto component_shift = klass->GetComponentSizeShift();
152*795d594fSAndroid Build Coastguard Worker   ObjPtr<Array> new_array =
153*795d594fSAndroid Build Coastguard Worker       Alloc(self, klass, new_length, component_shift, allocator_type);  // Invalidates klass.
154*795d594fSAndroid Build Coastguard Worker   if (LIKELY(new_array != nullptr)) {
155*795d594fSAndroid Build Coastguard Worker     memcpy(new_array->GetRawData(component_size, 0),
156*795d594fSAndroid Build Coastguard Worker            h_this->GetRawData(component_size, 0),
157*795d594fSAndroid Build Coastguard Worker            std::min(h_this->GetLength(), new_length) << component_shift);
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker   return new_array;
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker // Explicitly instantiate all the primitive array types.
163*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<uint8_t>;   // BooleanArray
164*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<int8_t>;    // ByteArray
165*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<uint16_t>;  // CharArray
166*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<double>;    // DoubleArray
167*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<float>;     // FloatArray
168*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<int32_t>;   // IntArray
169*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<int64_t>;   // LongArray
170*795d594fSAndroid Build Coastguard Worker template class PrimitiveArray<int16_t>;   // ShortArray
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker }  // namespace mirror
173*795d594fSAndroid Build Coastguard Worker }  // namespace art
174