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