Home | History | Annotate | Download | only in mirror
      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