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   // C style casts here since we sometimes have T be a pointer, or sometimes an integer
231   // (for stack traces).
232   if (kPointerSize == PointerSize::k64) {
233     return (T)static_cast<uintptr_t>(AsLongArray<kVerifyFlags>()->GetWithoutChecks(idx));
234   }
235   return (T)static_cast<uintptr_t>(AsIntArray<kVerifyFlags>()->GetWithoutChecks(idx));
236 }
237 template<typename T, PointerSize kPointerSize, VerifyObjectFlags kVerifyFlags>
GetElementPtrSizeUnchecked(uint32_t idx)238 inline T PointerArray::GetElementPtrSizeUnchecked(uint32_t idx) {
239   // C style casts here since we sometimes have T be a pointer, or sometimes an integer
240   // (for stack traces).
241   if (kPointerSize == PointerSize::k64) {
242     return (T)static_cast<uintptr_t>(AsLongArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
243   }
244   return (T)static_cast<uintptr_t>(AsIntArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
245 }
246 template<typename T, VerifyObjectFlags kVerifyFlags>
GetElementPtrSize(uint32_t idx,PointerSize ptr_size)247 inline T PointerArray::GetElementPtrSize(uint32_t idx, PointerSize ptr_size) {
248   if (ptr_size == PointerSize::k64) {
249     return GetElementPtrSize<T, PointerSize::k64, kVerifyFlags>(idx);
250   }
251   return GetElementPtrSize<T, PointerSize::k32, kVerifyFlags>(idx);
252 }
253 
254 template<bool kTransactionActive, bool kUnchecked>
SetElementPtrSize(uint32_t idx,uint64_t element,PointerSize ptr_size)255 inline void PointerArray::SetElementPtrSize(uint32_t idx, uint64_t element, PointerSize ptr_size) {
256   if (ptr_size == PointerSize::k64) {
257     (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(this)) : AsLongArray())->
258         SetWithoutChecks<kTransactionActive>(idx, element);
259   } else {
260     DCHECK_LE(element, static_cast<uint64_t>(0xFFFFFFFFu));
261     (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(this)) : AsIntArray())
262         ->SetWithoutChecks<kTransactionActive>(idx, static_cast<uint32_t>(element));
263   }
264 }
265 
266 template<bool kTransactionActive, bool kUnchecked, typename T>
SetElementPtrSize(uint32_t idx,T * element,PointerSize ptr_size)267 inline void PointerArray::SetElementPtrSize(uint32_t idx, T* element, PointerSize ptr_size) {
268   SetElementPtrSize<kTransactionActive, kUnchecked>(idx,
269                                                     reinterpret_cast<uintptr_t>(element),
270                                                     ptr_size);
271 }
272 
273 template <VerifyObjectFlags kVerifyFlags, typename Visitor>
Fixup(ObjPtr<mirror::PointerArray> dest,PointerSize pointer_size,const Visitor & visitor)274 inline void PointerArray::Fixup(ObjPtr<mirror::PointerArray> dest,
275                                 PointerSize pointer_size,
276                                 const Visitor& visitor) {
277   for (size_t i = 0, count = GetLength(); i < count; ++i) {
278     void* ptr = GetElementPtrSize<void*, kVerifyFlags>(i, pointer_size);
279     void* new_ptr = visitor(ptr);
280     if (ptr != new_ptr) {
281       dest->SetElementPtrSize<false, true>(i, new_ptr, pointer_size);
282     }
283   }
284 }
285 
286 template<bool kUnchecked>
Memcpy(int32_t dst_pos,ObjPtr<PointerArray> src,int32_t src_pos,int32_t count,PointerSize ptr_size)287 void PointerArray::Memcpy(int32_t dst_pos,
288                           ObjPtr<PointerArray> src,
289                           int32_t src_pos,
290                           int32_t count,
291                           PointerSize ptr_size) {
292   DCHECK(!Runtime::Current()->IsActiveTransaction());
293   DCHECK(!src.IsNull());
294   if (ptr_size == PointerSize::k64) {
295     ObjPtr<LongArray> l_this = (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(this))
296                                            : AsLongArray());
297     ObjPtr<LongArray> l_src = (kUnchecked ? ObjPtr<LongArray>::DownCast(ObjPtr<Object>(src))
298                                           : src->AsLongArray());
299     l_this->Memcpy(dst_pos, l_src, src_pos, count);
300   } else {
301     ObjPtr<IntArray> i_this = (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(this))
302                                           : AsIntArray());
303     ObjPtr<IntArray> i_src = (kUnchecked ? ObjPtr<IntArray>::DownCast(ObjPtr<Object>(src.Ptr()))
304                                          : src->AsIntArray());
305     i_this->Memcpy(dst_pos, i_src, src_pos, count);
306   }
307 }
308 
309 }  // namespace mirror
310 }  // namespace art
311 
312 #endif  // ART_RUNTIME_MIRROR_ARRAY_INL_H_
313