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_OBJECT_ARRAY_INL_H_ 18 #define ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_ 19 20 #include <string> 21 22 #include "object_array.h" 23 24 #include "array-inl.h" 25 #include "base/stringprintf.h" 26 #include "gc/heap.h" 27 #include "mirror/class.h" 28 #include "runtime.h" 29 #include "handle_scope-inl.h" 30 #include "thread.h" 31 #include "utils.h" 32 33 namespace art { 34 namespace mirror { 35 36 template<class T> 37 inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, Class* object_array_class, 38 int32_t length, gc::AllocatorType allocator_type) { 39 Array* array = Array::Alloc<true>(self, object_array_class, length, 40 ComponentSizeShiftWidth(sizeof(HeapReference<Object>)), 41 allocator_type); 42 if (UNLIKELY(array == nullptr)) { 43 return nullptr; 44 } else { 45 DCHECK_EQ(array->GetClass()->GetComponentSizeShift(), 46 ComponentSizeShiftWidth(sizeof(HeapReference<Object>))); 47 return array->AsObjectArray<T>(); 48 } 49 } 50 51 template<class T> 52 inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, Class* object_array_class, 53 int32_t length) { 54 return Alloc(self, object_array_class, length, 55 Runtime::Current()->GetHeap()->GetCurrentAllocator()); 56 } 57 58 template<class T> 59 inline T* ObjectArray<T>::Get(int32_t i) { 60 if (!CheckIsValidIndex(i)) { 61 DCHECK(Thread::Current()->IsExceptionPending()); 62 return nullptr; 63 } 64 return GetFieldObject<T>(OffsetOfElement(i)); 65 } 66 67 template<class T> template<VerifyObjectFlags kVerifyFlags> 68 inline bool ObjectArray<T>::CheckAssignable(T* object) { 69 if (object != nullptr) { 70 Class* element_class = GetClass<kVerifyFlags>()->GetComponentType(); 71 if (UNLIKELY(!object->InstanceOf(element_class))) { 72 ThrowArrayStoreException(object); 73 return false; 74 } 75 } 76 return true; 77 } 78 79 template<class T> 80 inline void ObjectArray<T>::Set(int32_t i, T* object) { 81 if (Runtime::Current()->IsActiveTransaction()) { 82 Set<true>(i, object); 83 } else { 84 Set<false>(i, object); 85 } 86 } 87 88 template<class T> 89 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> 90 inline void ObjectArray<T>::Set(int32_t i, T* object) { 91 if (CheckIsValidIndex(i) && CheckAssignable<kVerifyFlags>(object)) { 92 SetFieldObject<kTransactionActive, kCheckTransaction, kVerifyFlags>(OffsetOfElement(i), object); 93 } else { 94 DCHECK(Thread::Current()->IsExceptionPending()); 95 } 96 } 97 98 template<class T> 99 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> 100 inline void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) { 101 DCHECK(CheckIsValidIndex<kVerifyFlags>(i)); 102 DCHECK(CheckAssignable<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>(object)); 103 SetFieldObject<kTransactionActive, kCheckTransaction, kVerifyFlags>(OffsetOfElement(i), object); 104 } 105 106 template<class T> 107 template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> 108 inline void ObjectArray<T>::SetWithoutChecksAndWriteBarrier(int32_t i, T* object) { 109 DCHECK(CheckIsValidIndex<kVerifyFlags>(i)); 110 // TODO: enable this check. It fails when writing the image in ImageWriter::FixupObjectArray. 111 // DCHECK(CheckAssignable(object)); 112 SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction, kVerifyFlags>( 113 OffsetOfElement(i), object); 114 } 115 116 template<class T> 117 inline T* ObjectArray<T>::GetWithoutChecks(int32_t i) { 118 DCHECK(CheckIsValidIndex(i)); 119 return GetFieldObject<T>(OffsetOfElement(i)); 120 } 121 122 template<class T> 123 inline void ObjectArray<T>::AssignableMemmove(int32_t dst_pos, ObjectArray<T>* src, 124 int32_t src_pos, int32_t count) { 125 if (kIsDebugBuild) { 126 for (int i = 0; i < count; ++i) { 127 // The get will perform the VerifyObject. 128 src->GetWithoutChecks(src_pos + i); 129 } 130 } 131 // Perform the memmove using int memmove then perform the write barrier. 132 CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t)); 133 IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this); 134 IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src); 135 if (kUseReadBarrier) { 136 // TODO: Optimize this later? 137 const bool copy_forward = (src != this) || (dst_pos < src_pos) || (dst_pos - src_pos >= count); 138 if (copy_forward) { 139 // Forward copy. 140 for (int i = 0; i < count; ++i) { 141 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB. 142 Object* obj = src->GetWithoutChecks(src_pos + i); 143 SetWithoutChecks<false>(dst_pos + i, obj); 144 } 145 } else { 146 // Backward copy. 147 for (int i = count - 1; i >= 0; --i) { 148 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB. 149 Object* obj = src->GetWithoutChecks(src_pos + i); 150 SetWithoutChecks<false>(dst_pos + i, obj); 151 } 152 } 153 } else { 154 dstAsIntArray->Memmove(dst_pos, srcAsIntArray, src_pos, count); 155 } 156 Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); 157 if (kIsDebugBuild) { 158 for (int i = 0; i < count; ++i) { 159 // The get will perform the VerifyObject. 160 GetWithoutChecks(dst_pos + i); 161 } 162 } 163 } 164 165 template<class T> 166 inline void ObjectArray<T>::AssignableMemcpy(int32_t dst_pos, ObjectArray<T>* src, 167 int32_t src_pos, int32_t count) { 168 if (kIsDebugBuild) { 169 for (int i = 0; i < count; ++i) { 170 // The get will perform the VerifyObject. 171 src->GetWithoutChecks(src_pos + i); 172 } 173 } 174 // Perform the memmove using int memcpy then perform the write barrier. 175 CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t)); 176 IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this); 177 IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src); 178 if (kUseReadBarrier) { 179 // TODO: Optimize this later? 180 for (int i = 0; i < count; ++i) { 181 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB. 182 T* obj = src->GetWithoutChecks(src_pos + i); 183 SetWithoutChecks<false>(dst_pos + i, obj); 184 } 185 } else { 186 dstAsIntArray->Memcpy(dst_pos, srcAsIntArray, src_pos, count); 187 } 188 Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); 189 if (kIsDebugBuild) { 190 for (int i = 0; i < count; ++i) { 191 // The get will perform the VerifyObject. 192 GetWithoutChecks(dst_pos + i); 193 } 194 } 195 } 196 197 template<class T> 198 inline void ObjectArray<T>::AssignableCheckingMemcpy(int32_t dst_pos, ObjectArray<T>* src, 199 int32_t src_pos, int32_t count, 200 bool throw_exception) { 201 DCHECK_NE(this, src) 202 << "This case should be handled with memmove that handles overlaps correctly"; 203 // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that 204 // we know is assignable to the destination array's component type. 205 Class* dst_class = GetClass()->GetComponentType(); 206 Class* lastAssignableElementClass = dst_class; 207 208 Object* o = nullptr; 209 int i = 0; 210 for (; i < count; ++i) { 211 // The follow get operations force the objects to be verified. 212 // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB. 213 o = src->GetWithoutChecks(src_pos + i); 214 if (o == nullptr) { 215 // Null is always assignable. 216 SetWithoutChecks<false>(dst_pos + i, nullptr); 217 } else { 218 // TODO: use the underlying class reference to avoid uncompression when not necessary. 219 Class* o_class = o->GetClass(); 220 if (LIKELY(lastAssignableElementClass == o_class)) { 221 SetWithoutChecks<false>(dst_pos + i, o); 222 } else if (LIKELY(dst_class->IsAssignableFrom(o_class))) { 223 lastAssignableElementClass = o_class; 224 SetWithoutChecks<false>(dst_pos + i, o); 225 } else { 226 // Can't put this element into the array, break to perform write-barrier and throw 227 // exception. 228 break; 229 } 230 } 231 } 232 Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count); 233 if (UNLIKELY(i != count)) { 234 std::string actualSrcType(PrettyTypeOf(o)); 235 std::string dstType(PrettyTypeOf(this)); 236 Thread* self = Thread::Current(); 237 if (throw_exception) { 238 self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", 239 "source[%d] of type %s cannot be stored in destination array of type %s", 240 src_pos + i, actualSrcType.c_str(), dstType.c_str()); 241 } else { 242 LOG(FATAL) << StringPrintf("source[%d] of type %s cannot be stored in destination array of type %s", 243 src_pos + i, actualSrcType.c_str(), dstType.c_str()); 244 } 245 } 246 } 247 248 template<class T> 249 inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) { 250 DCHECK_GE(new_length, 0); 251 // We may get copied by a compacting GC. 252 StackHandleScope<1> hs(self); 253 Handle<ObjectArray<T>> h_this(hs.NewHandle(this)); 254 gc::Heap* heap = Runtime::Current()->GetHeap(); 255 gc::AllocatorType allocator_type = heap->IsMovableObject(this) ? heap->GetCurrentAllocator() : 256 heap->GetCurrentNonMovingAllocator(); 257 ObjectArray<T>* new_array = Alloc(self, GetClass(), new_length, allocator_type); 258 if (LIKELY(new_array != nullptr)) { 259 new_array->AssignableMemcpy(0, h_this.Get(), 0, std::min(h_this->GetLength(), new_length)); 260 } 261 return new_array; 262 } 263 264 template<class T> 265 inline MemberOffset ObjectArray<T>::OffsetOfElement(int32_t i) { 266 return MemberOffset(DataOffset(sizeof(HeapReference<Object>)).Int32Value() + 267 (i * sizeof(HeapReference<Object>))); 268 } 269 270 template<class T> template<const bool kVisitClass, typename Visitor> 271 void ObjectArray<T>::VisitReferences(const Visitor& visitor) { 272 if (kVisitClass) { 273 visitor(this, ClassOffset(), false); 274 } 275 const size_t length = static_cast<size_t>(GetLength()); 276 for (size_t i = 0; i < length; ++i) { 277 visitor(this, OffsetOfElement(i), false); 278 } 279 } 280 281 } // namespace mirror 282 } // namespace art 283 284 #endif // ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_ 285