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_INL_H_
18 #define ART_RUNTIME_MIRROR_ARRAY_INL_H_
19 
20 #include "array.h"
21 
22 #include <android-base/logging.h>
23 
24 #include "base/bit_utils.h"
25 #include "class.h"
26 #include "obj_ptr-inl.h"
27 #include "runtime.h"
28 #include "thread-current-inl.h"
29 
30 namespace art {
31 namespace mirror {
32 
ClassSize(PointerSize pointer_size)33 inline uint32_t Array::ClassSize(PointerSize pointer_size) {
34   uint32_t vtable_entries = Object::kVTableLength;
35   return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0, pointer_size);
36 }
37 
38 template<VerifyObjectFlags kVerifyFlags>
SizeOf()39 inline size_t Array::SizeOf() {
40   // No read barrier is needed for reading a constant primitive field through
41   // constant reference field chain. See ReadBarrierOption.
42   size_t component_size_shift =
43       GetClass<kVerifyFlags, kWithoutReadBarrier>()->GetComponentSizeShift();
44   // Don't need to check this since we already check this in GetClass.
45   int32_t component_count =
46       GetLength<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>();
47   // This is safe from overflow because the array was already allocated, so we know it's sane.
48   size_t header_size = DataOffset(1U << component_size_shift).SizeValue();
49   size_t data_size = component_count << component_size_shift;
50   return header_size + data_size;
51 }
52 
53 template<VerifyObjectFlags kVerifyFlags>
CheckIsValidIndex(int32_t index)54 inline bool Array::CheckIsValidIndex(int32_t index) {
55   if (UNLIKELY(static_cast<uint32_t>(index) >=
56                static_cast<uint32_t>(GetLength<kVerifyFlags>()))) {
57     ThrowArrayIndexOutOfBoundsException(index);
58     return false;
59   }
60   return true;
61 }
62 
63 template<typename T>
Get(int32_t i)64 inline T PrimitiveArray<T>::Get(int32_t i) {
65   if (!CheckIsValidIndex(i)) {
66     DCHECK(Thread::Current()->IsExceptionPending());
67     return T(0);
68   }
69   return GetWithoutChecks(i);
70 }
71 
72 template<typename T>
Set(int32_t i,T value)73 inline void PrimitiveArray<T>::Set(int32_t i, T value) {
74   if (Runtime::Current()->IsActiveTransaction()) {
75     Set<true>(i, value);
76   } else {
77     Set<false>(i, value);
78   }
79 }
80 
81 template<typename T>
82 template<bool kTransactionActive, bool kCheckTransaction>
Set(int32_t i,T value)83 inline void PrimitiveArray<T>::Set(int32_t i, T value) {
84   if (CheckIsValidIndex(i)) {
85     SetWithoutChecks<kTransactionActive, kCheckTransaction>(i, value);
86   } else {
87     DCHECK(Thread::Current()->IsExceptionPending());
88   }
89 }
90 
91 template<typename T>
92 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
SetWithoutChecks(int32_t i,T value)93 inline void PrimitiveArray<T>::SetWithoutChecks(int32_t i, T value) {
94   if (kCheckTransaction) {
95     DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
96   }
97   if (kTransactionActive) {
98     Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
99   }
100   DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
101   GetData()[i] = value;
102 }
103 // Backward copy where elements are of aligned appropriately for T. Count is in T sized units.
104 // Copies are guaranteed not to tear when the sizeof T is less-than 64bit.
105 template<typename T>
ArrayBackwardCopy(T * d,const T * s,int32_t count)106 static inline void ArrayBackwardCopy(T* d, const T* s, int32_t count) {
107   d += count;
108   s += count;
109   for (int32_t i = 0; i < count; ++i) {
110     d--;
111     s--;
112     *d = *s;
113   }
114 }
115 
116 // Forward copy where elements are of aligned appropriately for T. Count is in T sized units.
117 // Copies are guaranteed not to tear when the sizeof T is less-than 64bit.
118 template<typename T>
ArrayForwardCopy(T * d,const T * s,int32_t count)119 static inline void ArrayForwardCopy(T* d, const T* s, int32_t count) {
120   for (int32_t i = 0; i < count; ++i) {
121     *d = *s;
122     d++;
123     s++;
124   }
125 }
126 
127 template<class T>
Memmove(int32_t dst_pos,ObjPtr<PrimitiveArray<T>> src,int32_t src_pos,int32_t count)128 inline void PrimitiveArray<T>::Memmove(int32_t dst_pos,
129                                        ObjPtr<PrimitiveArray<T>> src,
130                                        int32_t src_pos,
131                                        int32_t count) {
132   if (UNLIKELY(count == 0)) {
133     return;
134   }
135   DCHECK_GE(dst_pos, 0);
136   DCHECK_GE(src_pos, 0);
137   DCHECK_GT(count, 0);
138   DCHECK(src != nullptr);
139   DCHECK_LT(dst_pos, GetLength());
140   DCHECK_LE(dst_pos, GetLength() - count);
141   DCHECK_LT(src_pos, src->GetLength());
142   DCHECK_LE(src_pos, src->GetLength() - count);
143 
144   // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3)
145   // in our implementation, because they may copy byte-by-byte.
146   if (LIKELY(src != this)) {
147     // Memcpy ok for guaranteed non-overlapping distinct arrays.
148     Memcpy(dst_pos, src, src_pos, count);
149   } else {
150     // Handle copies within the same array using the appropriate direction copy.
151     void* dst_raw = GetRawData(sizeof(T), dst_pos);
152     const void* src_raw = src->GetRawData(sizeof(T), src_pos);
153     if (sizeof(T) == sizeof(uint8_t)) {
154       uint8_t* d = reinterpret_cast<uint8_t*>(dst_raw);
155       const uint8_t* s = reinterpret_cast<const uint8_t*>(src_raw);
156       memmove(d, s, count);
157     } else {
158       const bool copy_forward = (dst_pos < src_pos) || (dst_pos - src_pos >= count);
159       if (sizeof(T) == sizeof(uint16_t)) {
160         uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw);
161         const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw);
162         if (copy_forward) {
163           ArrayForwardCopy<uint16_t>(d, s, count);
164         } else {
165           ArrayBackwardCopy<uint16_t>(d, s, count);
166         }
167       } else if (sizeof(T) == sizeof(uint32_t)) {
168         uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw);
169         const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw);
170         if (copy_forward) {
171           ArrayForwardCopy<uint32_t>(d, s, count);
172         } else {
173           ArrayBackwardCopy<uint32_t>(d, s, count);
174         }
175       } else {
176         DCHECK_EQ(sizeof(T), sizeof(uint64_t));
177         uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw);
178         const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw);
179         if (copy_forward) {
180           ArrayForwardCopy<uint64_t>(d, s, count);
181         } else {
182           ArrayBackwardCopy<uint64_t>(d, s, count);
183         }
184       }
185     }
186   }
187 }
188 
189 template<class T>
Memcpy(int32_t dst_pos,ObjPtr<PrimitiveArray<T>> src,int32_t src_pos,int32_t count)190 inline void PrimitiveArray<T>::Memcpy(int32_t dst_pos,
191                                       ObjPtr<PrimitiveArray<T>> src,
192                                       int32_t src_pos,
193                                       int32_t count) {
194   if (UNLIKELY(count == 0)) {
195     return;
196   }
197   DCHECK_GE(dst_pos, 0);
198   DCHECK_GE(src_pos, 0);
199   DCHECK_GT(count, 0);
200   DCHECK(src != nullptr);
201   DCHECK_LT(dst_pos, GetLength());
202   DCHECK_LE(dst_pos, GetLength() - count);
203   DCHECK_LT(src_pos, src->GetLength());
204   DCHECK_LE(src_pos, src->GetLength() - count);
205 
206   // Note for non-byte copies we can't rely on standard libc functions like memcpy(3) and memmove(3)
207   // in our implementation, because they may copy byte-by-byte.
208   void* dst_raw = GetRawData(sizeof(T), dst_pos);
209   const void* src_raw = src->GetRawData(sizeof(T), src_pos);
210   if (sizeof(T) == sizeof(uint8_t)) {
211     memcpy(dst_raw, src_raw, count);
212   } else if (sizeof(T) == sizeof(uint16_t)) {
213     uint16_t* d = reinterpret_cast<uint16_t*>(dst_raw);
214     const uint16_t* s = reinterpret_cast<const uint16_t*>(src_raw);
215     ArrayForwardCopy<uint16_t>(d, s, count);
216   } else if (sizeof(T) == sizeof(uint32_t)) {
217     uint32_t* d = reinterpret_cast<uint32_t*>(dst_raw);
218     const uint32_t* s = reinterpret_cast<const uint32_t*>(src_raw);
219     ArrayForwardCopy<uint32_t>(d, s, count);
220   } else {
221     DCHECK_EQ(sizeof(T), sizeof(uint64_t));
222     uint64_t* d = reinterpret_cast<uint64_t*>(dst_raw);
223     const uint64_t* s = reinterpret_cast<const uint64_t*>(src_raw);
224     ArrayForwardCopy<uint64_t>(d, s, count);
225   }
226 }
227 
228 template<typename T, PointerSize kPointerSize, VerifyObjectFlags kVerifyFlags>
GetElementPtrSize(uint32_t idx)229 inline T PointerArray::GetElementPtrSize(uint32_t idx) {
230   if (kPointerSize == PointerSize::k64) {
231     DCHECK(IsLongArray<kVerifyFlags>());
232   } else {
233     DCHECK(IsIntArray<kVerifyFlags>());
234   }
235   return GetElementPtrSizeUnchecked<T, kPointerSize, kVerifyFlags>(idx);
236 }
237 
238 template<typename T, PointerSize kPointerSize, VerifyObjectFlags kVerifyFlags>
GetElementPtrSizeUnchecked(uint32_t idx)239 inline T PointerArray::GetElementPtrSizeUnchecked(uint32_t idx) {
240   // C style casts here since we sometimes have T be a pointer, or sometimes an integer
241   // (for stack traces).
242   using ConversionType = typename std::conditional_t<std::is_pointer_v<T>, uintptr_t, T>;
243   if (kPointerSize == PointerSize::k64) {
244     uint64_t value =
245         static_cast<uint64_t>(AsLongArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
246     return (T) dchecked_integral_cast<ConversionType>(value);
247   } else {
248     uint32_t value =
249         static_cast<uint32_t>(AsIntArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
250     return (T) dchecked_integral_cast<ConversionType>(value);
251   }
252 }
253 
254 template<typename T, VerifyObjectFlags kVerifyFlags>
GetElementPtrSize(uint32_t idx,PointerSize ptr_size)255 inline T PointerArray::GetElementPtrSize(uint32_t idx, PointerSize ptr_size) {
256   if (ptr_size == PointerSize::k64) {
257     return GetElementPtrSize<T, PointerSize::k64, kVerifyFlags>(idx);
258   }
259   return GetElementPtrSize<T, PointerSize::k32, kVerifyFlags>(idx);
260 }
261 
262 template<bool kTransactionActive, bool kUnchecked>
SetElementPtrSize(uint32_t idx,uint64_t element,PointerSize ptr_size)263 inline void PointerArray::SetElementPtrSize(uint32_t idx, uint64_t element, PointerSize ptr_size) {
264   if (ptr_size == PointerSize::k64) {
265     (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(this)) : AsLongArray())->
266         SetWithoutChecks<kTransactionActive>(idx, element);
267   } else {
268     DCHECK_LE(element, static_cast<uint64_t>(0xFFFFFFFFu));
269     (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(this)) : AsIntArray())
270         ->SetWithoutChecks<kTransactionActive>(idx, static_cast<uint32_t>(element));
271   }
272 }
273 
274 template<bool kTransactionActive, bool kUnchecked, typename T>
SetElementPtrSize(uint32_t idx,T * element,PointerSize ptr_size)275 inline void PointerArray::SetElementPtrSize(uint32_t idx, T* element, PointerSize ptr_size) {
276   SetElementPtrSize<kTransactionActive, kUnchecked>(idx,
277                                                     reinterpret_cast<uintptr_t>(element),
278                                                     ptr_size);
279 }
280 
281 template <VerifyObjectFlags kVerifyFlags, typename Visitor>
Fixup(ObjPtr<mirror::PointerArray> dest,PointerSize pointer_size,const Visitor & visitor)282 inline void PointerArray::Fixup(ObjPtr<mirror::PointerArray> dest,
283                                 PointerSize pointer_size,
284                                 const Visitor& visitor) {
285   for (size_t i = 0, count = GetLength(); i < count; ++i) {
286     void* ptr = GetElementPtrSize<void*, kVerifyFlags>(i, pointer_size);
287     void* new_ptr = visitor(ptr);
288     if (ptr != new_ptr) {
289       dest->SetElementPtrSize<false, true>(i, new_ptr, pointer_size);
290     }
291   }
292 }
293 
294 template<bool kUnchecked>
Memcpy(int32_t dst_pos,ObjPtr<PointerArray> src,int32_t src_pos,int32_t count,PointerSize ptr_size)295 void PointerArray::Memcpy(int32_t dst_pos,
296                           ObjPtr<PointerArray> src,
297                           int32_t src_pos,
298                           int32_t count,
299                           PointerSize ptr_size) {
300   DCHECK(!Runtime::Current()->IsActiveTransaction());
301   DCHECK(!src.IsNull());
302   if (ptr_size == PointerSize::k64) {
303     ObjPtr<LongArray> l_this = (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(this))
304                                            : AsLongArray());
305     ObjPtr<LongArray> l_src = (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(src))
306                                           : src->AsLongArray());
307     l_this->Memcpy(dst_pos, l_src, src_pos, count);
308   } else {
309     ObjPtr<IntArray> i_this = (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(this))
310                                           : AsIntArray());
311     ObjPtr<IntArray> i_src = (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(src.Ptr()))
312                                          : src->AsIntArray());
313     i_this->Memcpy(dst_pos, i_src, src_pos, count);
314   }
315 }
316 
317 }  // namespace mirror
318 }  // namespace art
319 
320 #endif  // ART_RUNTIME_MIRROR_ARRAY_INL_H_
321