| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ART_RUNTIME_MIRROR_CLASS_EXT_INL_H_ |
| #define ART_RUNTIME_MIRROR_CLASS_EXT_INL_H_ |
| |
| #include "class_ext.h" |
| |
| #include "array-inl.h" |
| #include "art_method-inl.h" |
| #include "base/enums.h" |
| #include "base/globals.h" |
| #include "class_linker.h" |
| #include "handle_scope.h" |
| #include "jni/jni_internal.h" |
| #include "jni_id_type.h" |
| #include "mirror/array.h" |
| #include "mirror/object.h" |
| #include "object-inl.h" |
| #include "verify_object.h" |
| #include "well_known_classes.h" |
| |
| namespace art { |
| namespace mirror { |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::EnsureJniIdsArrayPresent(MemberOffset off, size_t count) { |
| ObjPtr<Object> existing( |
| GetFieldObject<Object, kVerifyFlags, kReadBarrierOption>(off)); |
| if (!existing.IsNull()) { |
| return true; |
| } |
| Thread* self = Thread::Current(); |
| StackHandleScope<2> hs(self); |
| Handle<ClassExt> h_this(hs.NewHandle(this)); |
| MutableHandle<Object> new_arr(hs.NewHandle<Object>(nullptr)); |
| if (UNLIKELY(Runtime::Current()->GetJniIdType() == JniIdType::kSwapablePointer)) { |
| new_arr.Assign(Runtime::Current()->GetJniIdManager()->GetPointerMarker()); |
| } else { |
| new_arr.Assign(Runtime::Current()->GetClassLinker()->AllocPointerArray(self, count)); |
| } |
| if (new_arr.IsNull()) { |
| // Fail. |
| self->AssertPendingOOMException(); |
| return false; |
| } |
| bool set; |
| // Set the ext_data_ field using CAS semantics. |
| if (Runtime::Current()->IsActiveTransaction()) { |
| set = h_this->CasFieldObject<true>( |
| off, nullptr, new_arr.Get(), CASMode::kStrong, std::memory_order_seq_cst); |
| } else { |
| set = h_this->CasFieldObject<false>( |
| off, nullptr, new_arr.Get(), CASMode::kStrong, std::memory_order_seq_cst); |
| } |
| if (kIsDebugBuild) { |
| ObjPtr<Object> ret( |
| set ? new_arr.Get() |
| : h_this->GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>(off)); |
| CHECK(!ret.IsNull()); |
| } |
| return true; |
| } |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::EnsureJMethodIDsArrayPresent(size_t count) { |
| return EnsureJniIdsArrayPresent<kVerifyFlags, kReadBarrierOption>( |
| MemberOffset(OFFSET_OF_OBJECT_MEMBER(ClassExt, jmethod_ids_)), count); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::EnsureStaticJFieldIDsArrayPresent(size_t count) { |
| return EnsureJniIdsArrayPresent<kVerifyFlags, kReadBarrierOption>( |
| MemberOffset(OFFSET_OF_OBJECT_MEMBER(ClassExt, static_jfield_ids_)), count); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::EnsureInstanceJFieldIDsArrayPresent(size_t count) { |
| return EnsureJniIdsArrayPresent<kVerifyFlags, kReadBarrierOption>( |
| MemberOffset(OFFSET_OF_OBJECT_MEMBER(ClassExt, instance_jfield_ids_)), count); |
| } |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<Object> ClassExt::GetInstanceJFieldIDs() { |
| return GetFieldObject<Object, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, instance_jfield_ids_)); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::HasInstanceFieldPointerIdMarker() { |
| ObjPtr<Object> arr(GetInstanceJFieldIDs<kVerifyFlags, kReadBarrierOption>()); |
| return !arr.IsNull() && !arr->IsArrayInstance(); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<PointerArray> ClassExt::GetInstanceJFieldIDsPointerArray() { |
| DCHECK(!HasInstanceFieldPointerIdMarker()); |
| return down_cast<PointerArray*>(GetInstanceJFieldIDs<kVerifyFlags, kReadBarrierOption>().Ptr()); |
| } |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<Object> ClassExt::GetStaticJFieldIDs() { |
| return GetFieldObject<Object, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, static_jfield_ids_)); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<PointerArray> ClassExt::GetStaticJFieldIDsPointerArray() { |
| DCHECK(!HasStaticFieldPointerIdMarker()); |
| return down_cast<PointerArray*>(GetStaticJFieldIDs<kVerifyFlags, kReadBarrierOption>().Ptr()); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::HasStaticFieldPointerIdMarker() { |
| ObjPtr<Object> arr(GetStaticJFieldIDs<kVerifyFlags, kReadBarrierOption>()); |
| return !arr.IsNull() && !arr->IsArrayInstance(); |
| } |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<Class> ClassExt::GetObsoleteClass() { |
| return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_class_)); |
| } |
| |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<Object> ClassExt::GetJMethodIDs() { |
| return GetFieldObject<Object, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, jmethod_ids_)); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<PointerArray> ClassExt::GetJMethodIDsPointerArray() { |
| DCHECK(!HasMethodPointerIdMarker()); |
| return down_cast<PointerArray*>(GetJMethodIDs<kVerifyFlags, kReadBarrierOption>().Ptr()); |
| } |
| template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline bool ClassExt::HasMethodPointerIdMarker() { |
| ObjPtr<Object> arr(GetJMethodIDs<kVerifyFlags, kReadBarrierOption>()); |
| return !arr.IsNull() && !arr->IsArrayInstance(); |
| } |
| |
| inline ObjPtr<Throwable> ClassExt::GetErroneousStateError() { |
| return GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(ClassExt, erroneous_state_error_)); |
| } |
| |
| template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<ObjectArray<DexCache>> ClassExt::GetObsoleteDexCaches() { |
| return GetFieldObject<ObjectArray<DexCache>, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_dex_caches_)); |
| } |
| |
| template<VerifyObjectFlags kVerifyFlags, |
| ReadBarrierOption kReadBarrierOption> |
| inline ObjPtr<PointerArray> ClassExt::GetObsoleteMethods() { |
| return GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>( |
| OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_methods_)); |
| } |
| |
| inline ObjPtr<Object> ClassExt::GetOriginalDexFile() { |
| return GetFieldObject<Object>(OFFSET_OF_OBJECT_MEMBER(ClassExt, original_dex_file_)); |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, bool kVisitProxyMethod, class Visitor> |
| void ClassExt::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) { |
| VisitMethods<kReadBarrierOption>([&](ArtMethod* method) { |
| method->VisitRoots<kReadBarrierOption, kVisitProxyMethod>(visitor, pointer_size); |
| }, pointer_size); |
| } |
| |
| template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> |
| void ClassExt::VisitDexCaches(DexCacheVisitor& visitor) { |
| ObjPtr<ObjectArray<DexCache>> arr(GetObsoleteDexCaches<kVerifyFlags, kReadBarrierOption>()); |
| if (!arr.IsNull()) { |
| int32_t len = arr->GetLength(); |
| for (int32_t i = 0; i < len; i++) { |
| ObjPtr<mirror::DexCache> dex_cache = arr->Get<kVerifyFlags, kReadBarrierOption>(i); |
| visitor.Visit(dex_cache); |
| } |
| } |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void ClassExt::VisitMethods(Visitor visitor, PointerSize pointer_size) { |
| ObjPtr<PointerArray> arr(GetObsoleteMethods<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!arr.IsNull()) { |
| int32_t len = arr->GetLength(); |
| for (int32_t i = 0; i < len; i++) { |
| ArtMethod* method = arr->GetElementPtrSize<ArtMethod*>(i, pointer_size); |
| if (method != nullptr) { |
| visitor(method); |
| } |
| } |
| } |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void ClassExt::VisitJMethodIDs(Visitor v) { |
| ObjPtr<Object> arr(GetJMethodIDs<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!arr.IsNull() && arr->IsArrayInstance()) { |
| ObjPtr<PointerArray> marr(down_cast<PointerArray*>(arr.Ptr())); |
| int32_t len = marr->GetLength(); |
| for (int32_t i = 0; i < len; i++) { |
| jmethodID id = marr->GetElementPtrSize<jmethodID>(i, kRuntimePointerSize); |
| if (id != nullptr) { |
| v(id, i); |
| } |
| } |
| } |
| } |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void ClassExt::VisitJFieldIDs(Visitor v) { |
| ObjPtr<Object> sarr_obj(GetStaticJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!sarr_obj.IsNull() && sarr_obj->IsArrayInstance()) { |
| ObjPtr<PointerArray> sarr(down_cast<PointerArray*>(sarr_obj->AsArray().Ptr())); |
| int32_t len = sarr->GetLength(); |
| for (int32_t i = 0; i < len; i++) { |
| jfieldID id = sarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize); |
| if (id != nullptr) { |
| v(id, i, true); |
| } |
| } |
| } |
| ObjPtr<PointerArray> iarr_obj(GetInstanceJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!iarr_obj.IsNull() && iarr_obj->IsArrayInstance()) { |
| ObjPtr<PointerArray> iarr(down_cast<PointerArray*>(iarr_obj->AsArray().Ptr())); |
| int32_t len = iarr->GetLength(); |
| for (int32_t i = 0; i < len; i++) { |
| jfieldID id = iarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize); |
| if (id != nullptr) { |
| v(id, i, false); |
| } |
| } |
| } |
| } |
| |
| } // namespace mirror |
| } // namespace art |
| |
| #endif // ART_RUNTIME_MIRROR_CLASS_EXT_INL_H_ |