| /* |
| * Copyright (C) 2011 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_REFVISITOR_INL_H_ |
| #define ART_RUNTIME_MIRROR_CLASS_REFVISITOR_INL_H_ |
| |
| #include "class-inl.h" |
| |
| #include "art_field-inl.h" |
| #include "class_ext-inl.h" |
| |
| namespace art { |
| namespace mirror { |
| |
| template <bool kVisitNativeRoots, |
| VerifyObjectFlags kVerifyFlags, |
| ReadBarrierOption kReadBarrierOption, |
| typename Visitor> |
| inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) { |
| VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor); |
| // Right after a class is allocated, but not yet loaded |
| // (ClassStatus::kNotReady, see ClassLinker::LoadClass()), GC may find it |
| // and scan it. IsTemp() may call Class::GetAccessFlags() but may |
| // fail in the DCHECK in Class::GetAccessFlags() because the class |
| // status is ClassStatus::kNotReady. To avoid it, rely on IsResolved() |
| // only. This is fine because a temp class never goes into the |
| // ClassStatus::kResolved state. |
| if (IsResolved<kVerifyFlags>()) { |
| // Temp classes don't ever populate imt/vtable or static fields and they are not even |
| // allocated with the right size for those. Also, unresolved classes don't have fields |
| // linked yet. |
| VisitStaticFieldsReferences<kVerifyFlags, kReadBarrierOption>(this, visitor); |
| } |
| if (kVisitNativeRoots) { |
| // Since this class is reachable, we must also visit the associated roots when we scan it. |
| VisitNativeRoots<kReadBarrierOption>( |
| visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); |
| } |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) { |
| VisitFields<kReadBarrierOption>([&](ArtField* field) REQUIRES_SHARED(art::Locks::mutator_lock_) { |
| field->VisitRoots(visitor); |
| if (kIsDebugBuild && IsResolved()) { |
| CHECK_EQ(field->GetDeclaringClass<kReadBarrierOption>(), this) |
| << GetStatus() << field->GetDeclaringClass()->PrettyClass() << " != " << PrettyClass(); |
| } |
| }); |
| // Don't use VisitMethods because we don't want to hit the class-ext methods twice. |
| for (ArtMethod& method : GetMethods(pointer_size)) { |
| method.VisitRoots<kReadBarrierOption>(visitor, pointer_size); |
| } |
| ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!ext.IsNull()) { |
| ext->VisitNativeRoots<kReadBarrierOption, Visitor>(visitor, pointer_size); |
| } |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void Class::VisitMethods(Visitor visitor, PointerSize pointer_size) { |
| for (ArtMethod& method : GetMethods(pointer_size)) { |
| visitor(&method); |
| } |
| ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>()); |
| if (!ext.IsNull()) { |
| ext->VisitMethods<kReadBarrierOption, Visitor>(visitor, pointer_size); |
| } |
| } |
| |
| template<ReadBarrierOption kReadBarrierOption, class Visitor> |
| void Class::VisitFields(Visitor visitor) { |
| for (ArtField& sfield : GetSFieldsUnchecked()) { |
| visitor(&sfield); |
| } |
| for (ArtField& ifield : GetIFieldsUnchecked()) { |
| visitor(&ifield); |
| } |
| } |
| |
| } // namespace mirror |
| } // namespace art |
| |
| #endif // ART_RUNTIME_MIRROR_CLASS_REFVISITOR_INL_H_ |