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