blob: 154302e0e834c9f9146e03ea081e23bdab90e77a [file] [log] [blame]
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001/*
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
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
18#define ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080019
20#include "object_array.h"
21
Andreas Gampe46ee31b2016-12-14 10:11:49 -080022#include <string>
23
24#include "android-base/stringprintf.h"
25
Ian Rogers7e70b002014-10-08 11:47:24 -070026#include "array-inl.h"
Andreas Gampec15a2f42017-04-21 12:09:39 -070027#include "class.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028#include "obj_ptr-inl.h"
29#include "object-inl.h"
Vladimir Marko557fece2019-03-26 14:29:41 +000030#include "read_barrier-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070031#include "runtime.h"
Andreas Gampe52ecb652018-10-24 15:18:21 -070032#include "thread-current-inl.h"
Mathieu Chartier88ea61e2018-06-20 17:45:41 -070033#include "write_barrier-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080034
35namespace art {
36namespace mirror {
37
Mathieu Chartierfbc31082016-01-24 11:59:56 -080038template<class T> template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
Vladimir Marko423bebb2019-03-26 15:17:21 +000039inline ObjPtr<T> ObjectArray<T>::Get(int32_t i) {
Vladimir Marko924ad502018-09-19 09:48:04 +010040 if (!CheckIsValidIndex<kVerifyFlags>(i)) {
Sebastien Hertzabff6432014-01-27 18:01:39 +010041 DCHECK(Thread::Current()->IsExceptionPending());
Mathieu Chartier2cebb242015-04-21 16:50:40 -070042 return nullptr;
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080043 }
Mathieu Chartierfbc31082016-01-24 11:59:56 -080044 return GetFieldObject<T, kVerifyFlags, kReadBarrierOption>(OffsetOfElement(i));
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080045}
46
Mathieu Chartier4e305412014-02-19 10:54:44 -080047template<class T> template<VerifyObjectFlags kVerifyFlags>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -070048inline bool ObjectArray<T>::CheckAssignable(ObjPtr<T> object) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -070049 if (object != nullptr) {
Vladimir Markoc524e9e2019-03-26 10:54:50 +000050 ObjPtr<Class> element_class = GetClass<kVerifyFlags>()->GetComponentType();
Sebastien Hertz6bdd8f42013-05-17 14:44:01 +020051 if (UNLIKELY(!object->InstanceOf(element_class))) {
52 ThrowArrayStoreException(object);
53 return false;
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080054 }
Sebastien Hertz6bdd8f42013-05-17 14:44:01 +020055 }
56 return true;
57}
58
59template<class T>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -070060inline void ObjectArray<T>::Set(int32_t i, ObjPtr<T> object) {
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010061 if (Runtime::Current()->IsActiveTransaction()) {
62 Set<true>(i, object);
63 } else {
64 Set<false>(i, object);
65 }
66}
67
68template<class T>
Mathieu Chartier4e305412014-02-19 10:54:44 -080069template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -070070inline void ObjectArray<T>::Set(int32_t i, ObjPtr<T> object) {
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070071 if (CheckIsValidIndex(i) && CheckAssignable<kVerifyFlags>(object)) {
72 SetFieldObject<kTransactionActive, kCheckTransaction, kVerifyFlags>(OffsetOfElement(i), object);
Sebastien Hertz6bdd8f42013-05-17 14:44:01 +020073 } else {
74 DCHECK(Thread::Current()->IsExceptionPending());
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080075 }
76}
77
78template<class T>
Mathieu Chartier4e305412014-02-19 10:54:44 -080079template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -070080inline void ObjectArray<T>::SetWithoutChecks(int32_t i, ObjPtr<T> object) {
Mathieu Chartier4e305412014-02-19 10:54:44 -080081 DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
82 DCHECK(CheckAssignable<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>(object));
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070083 SetFieldObject<kTransactionActive, kCheckTransaction, kVerifyFlags>(OffsetOfElement(i), object);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080084}
85
86template<class T>
Mathieu Chartier4e305412014-02-19 10:54:44 -080087template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -070088inline void ObjectArray<T>::SetWithoutChecksAndWriteBarrier(int32_t i, ObjPtr<T> object) {
Mathieu Chartier4e305412014-02-19 10:54:44 -080089 DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
Ian Rogersef7d42f2014-01-06 12:55:46 -080090 // TODO: enable this check. It fails when writing the image in ImageWriter::FixupObjectArray.
Sebastien Hertzabff6432014-01-27 18:01:39 +010091 // DCHECK(CheckAssignable(object));
Mathieu Chartier4e305412014-02-19 10:54:44 -080092 SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction, kVerifyFlags>(
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070093 OffsetOfElement(i), object);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080094}
95
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -080096template<class T> template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
Vladimir Marko423bebb2019-03-26 15:17:21 +000097inline ObjPtr<T> ObjectArray<T>::GetWithoutChecks(int32_t i) {
Sebastien Hertzabff6432014-01-27 18:01:39 +010098 DCHECK(CheckIsValidIndex(i));
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -080099 return GetFieldObject<T, kVerifyFlags, kReadBarrierOption>(OffsetOfElement(i));
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800100}
101
102template<class T>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -0700103inline void ObjectArray<T>::AssignableMemmove(int32_t dst_pos,
104 ObjPtr<ObjectArray<T>> src,
105 int32_t src_pos,
106 int32_t count) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800107 if (kIsDebugBuild) {
108 for (int i = 0; i < count; ++i) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700109 // The get will perform the VerifyObject.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800110 src->GetWithoutChecks(src_pos + i);
111 }
112 }
113 // Perform the memmove using int memmove then perform the write barrier.
Roland Levillain33d69032015-06-18 18:20:59 +0100114 static_assert(sizeof(HeapReference<T>) == sizeof(uint32_t),
115 "art::mirror::HeapReference<T> and uint32_t have different sizes.");
Mathieu Chartierfec13d42016-10-07 12:59:33 -0700116 // TODO: Optimize this later?
117 // We can't use memmove since it does not handle read barriers and may do by per byte copying.
118 // See b/32012820.
119 const bool copy_forward = (src != this) || (dst_pos < src_pos) || (dst_pos - src_pos >= count);
120 if (copy_forward) {
121 // Forward copy.
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800122 bool baker_non_gray_case = false;
123 if (kUseReadBarrier && kUseBakerReadBarrier) {
124 uintptr_t fake_address_dependency;
125 if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
126 baker_non_gray_case = true;
Hiroshi Yamauchi6013f772016-11-16 13:30:17 -0800127 DCHECK_EQ(fake_address_dependency, 0U);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800128 src.Assign(reinterpret_cast<ObjectArray<T>*>(
129 reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
130 for (int i = 0; i < count; ++i) {
131 // We can skip the RB here because 'src' isn't gray.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000132 ObjPtr<T> obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800133 src_pos + i);
134 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
135 }
136 }
137 }
138 if (!baker_non_gray_case) {
139 for (int i = 0; i < count; ++i) {
140 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000141 ObjPtr<T> obj = src->GetWithoutChecks(src_pos + i);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800142 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
143 }
Hiroshi Yamauchi79719282014-04-10 12:46:22 -0700144 }
145 } else {
Mathieu Chartierfec13d42016-10-07 12:59:33 -0700146 // Backward copy.
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800147 bool baker_non_gray_case = false;
148 if (kUseReadBarrier && kUseBakerReadBarrier) {
149 uintptr_t fake_address_dependency;
150 if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
151 baker_non_gray_case = true;
Hiroshi Yamauchi6013f772016-11-16 13:30:17 -0800152 DCHECK_EQ(fake_address_dependency, 0U);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800153 src.Assign(reinterpret_cast<ObjectArray<T>*>(
154 reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
155 for (int i = count - 1; i >= 0; --i) {
156 // We can skip the RB here because 'src' isn't gray.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000157 ObjPtr<T> obj = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800158 src_pos + i);
159 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
160 }
161 }
162 }
163 if (!baker_non_gray_case) {
164 for (int i = count - 1; i >= 0; --i) {
165 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000166 ObjPtr<T> obj = src->GetWithoutChecks(src_pos + i);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800167 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
168 }
Mathieu Chartierfec13d42016-10-07 12:59:33 -0700169 }
Hiroshi Yamauchi79719282014-04-10 12:46:22 -0700170 }
Mathieu Chartier88ea61e2018-06-20 17:45:41 -0700171 WriteBarrier::ForArrayWrite(this, dst_pos, count);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800172 if (kIsDebugBuild) {
173 for (int i = 0; i < count; ++i) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700174 // The get will perform the VerifyObject.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800175 GetWithoutChecks(dst_pos + i);
176 }
177 }
178}
179
180template<class T>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -0700181inline void ObjectArray<T>::AssignableMemcpy(int32_t dst_pos,
182 ObjPtr<ObjectArray<T>> src,
183 int32_t src_pos,
184 int32_t count) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800185 if (kIsDebugBuild) {
186 for (int i = 0; i < count; ++i) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700187 // The get will perform the VerifyObject.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800188 src->GetWithoutChecks(src_pos + i);
189 }
190 }
191 // Perform the memmove using int memcpy then perform the write barrier.
Roland Levillain33d69032015-06-18 18:20:59 +0100192 static_assert(sizeof(HeapReference<T>) == sizeof(uint32_t),
193 "art::mirror::HeapReference<T> and uint32_t have different sizes.");
Mathieu Chartierfec13d42016-10-07 12:59:33 -0700194 // TODO: Optimize this later?
195 // We can't use memmove since it does not handle read barriers and may do by per byte copying.
196 // See b/32012820.
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800197 bool baker_non_gray_case = false;
198 if (kUseReadBarrier && kUseBakerReadBarrier) {
199 uintptr_t fake_address_dependency;
200 if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
201 baker_non_gray_case = true;
Hiroshi Yamauchi6013f772016-11-16 13:30:17 -0800202 DCHECK_EQ(fake_address_dependency, 0U);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800203 src.Assign(reinterpret_cast<ObjectArray<T>*>(
204 reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
205 for (int i = 0; i < count; ++i) {
206 // We can skip the RB here because 'src' isn't gray.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000207 ObjPtr<Object> obj =
208 src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(src_pos + i);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800209 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
210 }
211 }
212 }
213 if (!baker_non_gray_case) {
214 for (int i = 0; i < count; ++i) {
215 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
Vladimir Marko423bebb2019-03-26 15:17:21 +0000216 ObjPtr<T> obj = src->GetWithoutChecks(src_pos + i);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800217 SetWithoutChecksAndWriteBarrier<false>(dst_pos + i, obj);
218 }
Hiroshi Yamauchi79719282014-04-10 12:46:22 -0700219 }
Mathieu Chartier88ea61e2018-06-20 17:45:41 -0700220 WriteBarrier::ForArrayWrite(this, dst_pos, count);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800221 if (kIsDebugBuild) {
222 for (int i = 0; i < count; ++i) {
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700223 // The get will perform the VerifyObject.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800224 GetWithoutChecks(dst_pos + i);
225 }
226 }
227}
228
229template<class T>
Andreas Gampe85a098a2016-03-31 13:30:53 -0700230template<bool kTransactionActive>
Mathieu Chartier1a5337f2016-10-13 13:48:23 -0700231inline void ObjectArray<T>::AssignableCheckingMemcpy(int32_t dst_pos,
232 ObjPtr<ObjectArray<T>> src,
233 int32_t src_pos,
234 int32_t count,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800235 bool throw_exception) {
236 DCHECK_NE(this, src)
237 << "This case should be handled with memmove that handles overlaps correctly";
238 // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that
239 // we know is assignable to the destination array's component type.
Vladimir Markoc524e9e2019-03-26 10:54:50 +0000240 ObjPtr<Class> dst_class = GetClass()->GetComponentType();
241 ObjPtr<Class> lastAssignableElementClass = dst_class;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800242
Vladimir Markoc524e9e2019-03-26 10:54:50 +0000243 ObjPtr<T> o = nullptr;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800244 int i = 0;
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800245 bool baker_non_gray_case = false;
246 if (kUseReadBarrier && kUseBakerReadBarrier) {
247 uintptr_t fake_address_dependency;
248 if (!ReadBarrier::IsGray(src.Ptr(), &fake_address_dependency)) {
249 baker_non_gray_case = true;
Hiroshi Yamauchi6013f772016-11-16 13:30:17 -0800250 DCHECK_EQ(fake_address_dependency, 0U);
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800251 src.Assign(reinterpret_cast<ObjectArray<T>*>(
252 reinterpret_cast<uintptr_t>(src.Ptr()) | fake_address_dependency));
253 for (; i < count; ++i) {
254 // The follow get operations force the objects to be verified.
255 // We can skip the RB here because 'src' isn't gray.
256 o = src->template GetWithoutChecks<kDefaultVerifyFlags, kWithoutReadBarrier>(
257 src_pos + i);
258 if (o == nullptr) {
259 // Null is always assignable.
260 SetWithoutChecks<kTransactionActive>(dst_pos + i, nullptr);
261 } else {
262 // TODO: use the underlying class reference to avoid uncompression when not necessary.
Vladimir Markoc524e9e2019-03-26 10:54:50 +0000263 ObjPtr<Class> o_class = o->GetClass();
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800264 if (LIKELY(lastAssignableElementClass == o_class)) {
265 SetWithoutChecks<kTransactionActive>(dst_pos + i, o);
266 } else if (LIKELY(dst_class->IsAssignableFrom(o_class))) {
267 lastAssignableElementClass = o_class;
268 SetWithoutChecks<kTransactionActive>(dst_pos + i, o);
269 } else {
270 // Can't put this element into the array, break to perform write-barrier and throw
271 // exception.
272 break;
273 }
274 }
275 }
276 }
277 }
278 if (!baker_non_gray_case) {
279 for (; i < count; ++i) {
280 // The follow get operations force the objects to be verified.
281 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
282 o = src->GetWithoutChecks(src_pos + i);
283 if (o == nullptr) {
284 // Null is always assignable.
285 SetWithoutChecks<kTransactionActive>(dst_pos + i, nullptr);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800286 } else {
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800287 // TODO: use the underlying class reference to avoid uncompression when not necessary.
Vladimir Markodfc0de72019-04-01 10:57:55 +0100288 ObjPtr<Class> o_class = o->GetClass();
Hiroshi Yamauchie43b80e2016-11-14 13:42:50 -0800289 if (LIKELY(lastAssignableElementClass == o_class)) {
290 SetWithoutChecks<kTransactionActive>(dst_pos + i, o);
291 } else if (LIKELY(dst_class->IsAssignableFrom(o_class))) {
292 lastAssignableElementClass = o_class;
293 SetWithoutChecks<kTransactionActive>(dst_pos + i, o);
294 } else {
295 // Can't put this element into the array, break to perform write-barrier and throw
296 // exception.
297 break;
298 }
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800299 }
300 }
Ian Rogersef7d42f2014-01-06 12:55:46 -0800301 }
Mathieu Chartier88ea61e2018-06-20 17:45:41 -0700302 WriteBarrier::ForArrayWrite(this, dst_pos, count);
Ian Rogersef7d42f2014-01-06 12:55:46 -0800303 if (UNLIKELY(i != count)) {
David Sehr709b0702016-10-13 09:12:37 -0700304 std::string actualSrcType(mirror::Object::PrettyTypeOf(o));
305 std::string dstType(PrettyTypeOf());
Ian Rogersef7d42f2014-01-06 12:55:46 -0800306 Thread* self = Thread::Current();
Andreas Gampe46ee31b2016-12-14 10:11:49 -0800307 std::string msg = android::base::StringPrintf(
308 "source[%d] of type %s cannot be stored in destination array of type %s",
309 src_pos + i,
310 actualSrcType.c_str(),
311 dstType.c_str());
Ian Rogersef7d42f2014-01-06 12:55:46 -0800312 if (throw_exception) {
Andreas Gampe46ee31b2016-12-14 10:11:49 -0800313 self->ThrowNewException("Ljava/lang/ArrayStoreException;", msg.c_str());
Ian Rogersef7d42f2014-01-06 12:55:46 -0800314 } else {
Andreas Gampe46ee31b2016-12-14 10:11:49 -0800315 LOG(FATAL) << msg;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800316 }
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800317 }
318}
319
320template<class T>
Ian Rogersef7d42f2014-01-06 12:55:46 -0800321inline MemberOffset ObjectArray<T>::OffsetOfElement(int32_t i) {
Mathieu Chartier1a5337f2016-10-13 13:48:23 -0700322 return MemberOffset(DataOffset(kHeapReferenceSize).Int32Value() + (i * kHeapReferenceSize));
Ian Rogersef7d42f2014-01-06 12:55:46 -0800323}
324
Mathieu Chartier059ef3d2015-08-18 13:54:21 -0700325template<class T> template<typename Visitor>
Hiroshi Yamauchi723e6ce2015-10-28 20:59:47 -0700326inline void ObjectArray<T>::VisitReferences(const Visitor& visitor) {
Mathieu Chartier407f7022014-02-18 14:37:05 -0800327 const size_t length = static_cast<size_t>(GetLength());
328 for (size_t i = 0; i < length; ++i) {
329 visitor(this, OffsetOfElement(i), false);
330 }
331}
332
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800333} // namespace mirror
334} // namespace art
335
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700336#endif // ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_