xref: /aosp_15_r20/art/runtime/mirror/array.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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_H_
18 #define ART_RUNTIME_MIRROR_ARRAY_H_
19 
20 #include "base/bit_utils.h"
21 #include "base/macros.h"
22 #include "base/pointer_size.h"
23 #include "obj_ptr.h"
24 #include "object.h"
25 
26 namespace art HIDDEN {
27 
28 namespace gc {
29 enum AllocatorType : char;
30 }  // namespace gc
31 
32 template<class T> class Handle;
33 class Thread;
34 
35 namespace mirror {
36 
37 class MANAGED Array : public Object {
38  public:
39   static constexpr size_t kFirstElementOffset = 12u;
40 
41   // The size of a java.lang.Class representing an array.
42   static uint32_t ClassSize(PointerSize pointer_size);
43 
44   // Allocates an array with the given properties, if kFillUsable is true the array will be of at
45   // least component_count size, however, if there's usable space at the end of the allocation the
46   // array will fill it.
47   template <bool kIsInstrumented = true, bool kFillUsable = false>
48   ALWAYS_INLINE static ObjPtr<Array> Alloc(Thread* self,
49                                            ObjPtr<Class> array_class,
50                                            int32_t component_count,
51                                            size_t component_size_shift,
52                                            gc::AllocatorType allocator_type)
53       REQUIRES_SHARED(Locks::mutator_lock_)
54       REQUIRES(!Roles::uninterruptible_);
55 
56   static ObjPtr<Array> CreateMultiArray(Thread* self,
57                                         Handle<Class> element_class,
58                                         Handle<IntArray> dimensions)
59       REQUIRES_SHARED(Locks::mutator_lock_)
60       REQUIRES(!Roles::uninterruptible_);
61 
62   template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
63   size_t SizeOf(size_t component_size_shift) REQUIRES_SHARED(Locks::mutator_lock_);
64   template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
65             ReadBarrierOption kReadBarrierOption = kWithoutReadBarrier>
66   size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_);
67   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
GetLength()68   ALWAYS_INLINE int32_t GetLength() REQUIRES_SHARED(Locks::mutator_lock_) {
69     return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Array, length_));
70   }
71 
SetLength(int32_t length)72   void SetLength(int32_t length) REQUIRES_SHARED(Locks::mutator_lock_) {
73     DCHECK_GE(length, 0);
74     // We use non transactional version since we can't undo this write. We also disable checking
75     // since it would fail during a transaction.
76     SetField32<false, false, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Array, length_), length);
77   }
78 
LengthOffset()79   static constexpr MemberOffset LengthOffset() {
80     return OFFSET_OF_OBJECT_MEMBER(Array, length_);
81   }
82 
DataOffset(size_t component_size)83   static constexpr MemberOffset DataOffset(size_t component_size) {
84     DCHECK(IsPowerOfTwo(component_size)) << component_size;
85     size_t data_offset = RoundUp(OFFSETOF_MEMBER(Array, first_element_), component_size);
86     DCHECK_EQ(RoundUp(data_offset, component_size), data_offset)
87         << "Array data offset isn't aligned with component size";
88     return MemberOffset(data_offset);
89   }
90   template <size_t kComponentSize>
DataOffset()91   static constexpr MemberOffset DataOffset() {
92     static_assert(IsPowerOfTwo(kComponentSize), "Invalid component size");
93     constexpr size_t data_offset = RoundUp(kFirstElementOffset, kComponentSize);
94     static_assert(RoundUp(data_offset, kComponentSize) == data_offset, "RoundUp fail");
95     return MemberOffset(data_offset);
96   }
97 
FirstElementOffset()98   static constexpr size_t FirstElementOffset() {
99     return OFFSETOF_MEMBER(Array, first_element_);
100   }
101 
GetRawData(size_t component_size,int32_t index)102   void* GetRawData(size_t component_size, int32_t index)
103       REQUIRES_SHARED(Locks::mutator_lock_) {
104     intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value() +
105         + (index * component_size);
106     return reinterpret_cast<void*>(data);
107   }
108   template <size_t kComponentSize>
GetRawData(int32_t index)109   void* GetRawData(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_) {
110     intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset<kComponentSize>().Int32Value() +
111         + (index * kComponentSize);
112     return reinterpret_cast<void*>(data);
113   }
114 
GetRawData(size_t component_size,int32_t index)115   const void* GetRawData(size_t component_size, int32_t index) const {
116     intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset(component_size).Int32Value() +
117         + (index * component_size);
118     return reinterpret_cast<void*>(data);
119   }
120   template <size_t kComponentSize>
GetRawData(int32_t index)121   const void* GetRawData(int32_t index) const {
122     intptr_t data = reinterpret_cast<intptr_t>(this) + DataOffset<kComponentSize>().Int32Value() +
123         + (index * kComponentSize);
124     return reinterpret_cast<void*>(data);
125   }
126 
127   // Returns true if the index is valid. If not, throws an ArrayIndexOutOfBoundsException and
128   // returns false.
129   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
130   ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_);
131 
132   EXPORT static ObjPtr<Array> CopyOf(Handle<Array> h_this, Thread* self, int32_t new_length)
133       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
134 
135  protected:
136   EXPORT void ThrowArrayStoreException(ObjPtr<Object> object) REQUIRES_SHARED(Locks::mutator_lock_)
137       REQUIRES(!Roles::uninterruptible_);
138 
139  private:
140   EXPORT void ThrowArrayIndexOutOfBoundsException(int32_t index)
141       REQUIRES_SHARED(Locks::mutator_lock_);
142 
143   // The number of array elements.
144   // We only use the field indirectly using the LengthOffset() method.
145   [[maybe_unused]] int32_t length_;
146   // Marker for the data (used by generated code)
147   // We only use the field indirectly using the DataOffset() method.
148   [[maybe_unused]] uint32_t first_element_[0];
149 
150   DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
151 };
152 
153 template<typename T>
154 class MANAGED PrimitiveArray : public Array {
155  public:
156   MIRROR_CLASS("[Z");
157   MIRROR_CLASS("[B");
158   MIRROR_CLASS("[C");
159   MIRROR_CLASS("[S");
160   MIRROR_CLASS("[I");
161   MIRROR_CLASS("[J");
162   MIRROR_CLASS("[F");
163   MIRROR_CLASS("[D");
164 
165   using ElementType = T;
166 
167   EXPORT static ObjPtr<PrimitiveArray<T>> Alloc(Thread* self, size_t length)
168       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
169 
170   EXPORT static ObjPtr<PrimitiveArray<T>> AllocateAndFill(Thread* self,
171                                                           const T* data,
172                                                           size_t length)
173       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
174 
GetData()175   const T* GetData() const ALWAYS_INLINE  REQUIRES_SHARED(Locks::mutator_lock_) {
176     return reinterpret_cast<const T*>(GetRawData<sizeof(T)>(0));
177   }
178 
GetData()179   T* GetData() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
180     return reinterpret_cast<T*>(GetRawData<sizeof(T)>(0));
181   }
182 
183   T Get(int32_t i) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_);
184 
GetWithoutChecks(int32_t i)185   T GetWithoutChecks(int32_t i) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
186     DCHECK(CheckIsValidIndex(i)) << "i=" << i << " length=" << GetLength();
187     return GetData()[i];
188   }
189 
190   void Set(int32_t i, T value) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_);
191 
192   // TODO fix thread safety analysis broken by the use of template. This should be
193   // REQUIRES_SHARED(Locks::mutator_lock_).
194   template<bool kTransactionActive, bool kCheckTransaction = true>
195   void Set(int32_t i, T value) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
196 
197   // TODO fix thread safety analysis broken by the use of template. This should be
198   // REQUIRES_SHARED(Locks::mutator_lock_).
199   template<bool kTransactionActive,
200            bool kCheckTransaction = true,
201            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
202   void SetWithoutChecks(int32_t i, T value) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
203 
204   /*
205    * Works like memmove(), except we guarantee not to allow tearing of array values (ie using
206    * smaller than element size copies). Arguments are assumed to be within the bounds of the array
207    * and the arrays non-null.
208    */
209   void Memmove(int32_t dst_pos, ObjPtr<PrimitiveArray<T>> src, int32_t src_pos, int32_t count)
210       REQUIRES_SHARED(Locks::mutator_lock_);
211 
212   /*
213    * Works like memcpy(), except we guarantee not to allow tearing of array values (ie using
214    * smaller than element size copies). Arguments are assumed to be within the bounds of the array
215    * and the arrays non-null.
216    */
217   EXPORT void Memcpy(int32_t dst_pos, ObjPtr<PrimitiveArray<T>> src, int32_t src_pos, int32_t count)
218       REQUIRES_SHARED(Locks::mutator_lock_);
219 
220  private:
221   DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
222 };
223 
224 // Declare the different primitive arrays. Instantiations will be in array.cc.
225 extern template class PrimitiveArray<uint8_t>;   // BooleanArray
226 extern template class PrimitiveArray<int8_t>;    // ByteArray
227 extern template class PrimitiveArray<uint16_t>;  // CharArray
228 extern template class PrimitiveArray<double>;    // DoubleArray
229 extern template class PrimitiveArray<float>;     // FloatArray
230 extern template class PrimitiveArray<int32_t>;   // IntArray
231 extern template class PrimitiveArray<int64_t>;   // LongArray
232 extern template class PrimitiveArray<int16_t>;   // ShortArray
233 
234 // Either an IntArray or a LongArray.
235 class PointerArray : public Array {
236  public:
237   template<typename T, VerifyObjectFlags kVerifyFlags = kVerifyNone>
238   T GetElementPtrSize(uint32_t idx, PointerSize ptr_size)
239       REQUIRES_SHARED(Locks::mutator_lock_);
240   template<typename T, PointerSize kPtrSize, VerifyObjectFlags kVerifyFlags = kVerifyNone>
241   T GetElementPtrSize(uint32_t idx)
242       REQUIRES_SHARED(Locks::mutator_lock_);
243   // Same as GetElementPtrSize, but uses unchecked version of array conversion. It is thus not
244   // checked whether kPtrSize matches the underlying array. Only use after at least one invocation
245   // of GetElementPtrSize!
246   template<typename T, PointerSize kPtrSize, VerifyObjectFlags kVerifyFlags = kVerifyNone>
247   T GetElementPtrSizeUnchecked(uint32_t idx)
248       REQUIRES_SHARED(Locks::mutator_lock_);
249 
250   template<VerifyObjectFlags kVerifyFlags = kVerifyNone>
ElementAddress(size_t index,PointerSize ptr_size)251   void** ElementAddress(size_t index, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_) {
252     DCHECK_LT(index, static_cast<size_t>(GetLength<kVerifyFlags>()));
253     return reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(this) +
254                                     Array::DataOffset(static_cast<size_t>(ptr_size)).Uint32Value() +
255                                     static_cast<size_t>(ptr_size) * index);
256   }
257 
258   template<bool kTransactionActive = false, bool kCheckTransaction = true, bool kUnchecked = false>
259   void SetElementPtrSize(uint32_t idx, uint64_t element, PointerSize ptr_size)
260       REQUIRES_SHARED(Locks::mutator_lock_);
261   template<bool kTransactionActive = false,
262            bool kCheckTransaction = true,
263            bool kUnchecked = false,
264            typename T>
265   void SetElementPtrSize(uint32_t idx, T* element, PointerSize ptr_size)
266       REQUIRES_SHARED(Locks::mutator_lock_);
267 
268   // Fixup the pointers in the dest arrays by passing our pointers through the visitor. Only copies
269   // to dest if visitor(source_ptr) != source_ptr.
270   template <VerifyObjectFlags kVerifyFlags = kVerifyNone, typename Visitor>
271   void Fixup(mirror::PointerArray* dest, PointerSize pointer_size, const Visitor& visitor)
272       REQUIRES_SHARED(Locks::mutator_lock_);
273 
274   // Works like memcpy(), except we guarantee not to allow tearing of array values (ie using smaller
275   // than element size copies). Arguments are assumed to be within the bounds of the array and the
276   // arrays non-null. Cannot be called in an active transaction.
277   template<bool kUnchecked = false>
278   void Memcpy(int32_t dst_pos,
279               ObjPtr<PointerArray> src,
280               int32_t src_pos,
281               int32_t count,
282               PointerSize pointer_size)
283       REQUIRES_SHARED(Locks::mutator_lock_);
284 };
285 
286 }  // namespace mirror
287 }  // namespace art
288 
289 #endif  // ART_RUNTIME_MIRROR_ARRAY_H_
290