|  | /* | 
|  | * 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_CLASS_LINKER_H_ | 
|  | #define ART_RUNTIME_CLASS_LINKER_H_ | 
|  |  | 
|  | #include <list> | 
|  | #include <map> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <type_traits> | 
|  | #include <unordered_map> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/enums.h" | 
|  | #include "base/hash_map.h" | 
|  | #include "base/intrusive_forward_list.h" | 
|  | #include "base/locks.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/mutex.h" | 
|  | #include "dex/class_accessor.h" | 
|  | #include "dex/dex_file_types.h" | 
|  | #include "gc_root.h" | 
|  | #include "handle.h" | 
|  | #include "jni.h" | 
|  | #include "mirror/class.h" | 
|  | #include "mirror/object.h" | 
|  | #include "oat_file.h" | 
|  | #include "verifier/verifier_enums.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | class ArtField; | 
|  | class ArtMethod; | 
|  | class ClassHierarchyAnalysis; | 
|  | enum class ClassRoot : uint32_t; | 
|  | class ClassTable; | 
|  | class DexFile; | 
|  | template<class T> class Handle; | 
|  | class ImtConflictTable; | 
|  | template<typename T> class LengthPrefixedArray; | 
|  | template<class T> class MutableHandle; | 
|  | class InternTable; | 
|  | class LinearAlloc; | 
|  | class OatFile; | 
|  | template<class T> class ObjectLock; | 
|  | class Runtime; | 
|  | class ScopedObjectAccessAlreadyRunnable; | 
|  | class SdkChecker; | 
|  | template<size_t kNumReferences> class PACKED(4) StackHandleScope; | 
|  | class Thread; | 
|  |  | 
|  | enum VisitRootFlags : uint8_t; | 
|  |  | 
|  | namespace dex { | 
|  | struct ClassDef; | 
|  | struct MethodHandleItem; | 
|  | }  // namespace dex | 
|  |  | 
|  | namespace gc { | 
|  | namespace space { | 
|  | class ImageSpace; | 
|  | }  // namespace space | 
|  | }  // namespace gc | 
|  |  | 
|  | namespace linker { | 
|  | struct CompilationHelper; | 
|  | class ImageWriter; | 
|  | class OatWriter; | 
|  | }  // namespace linker | 
|  |  | 
|  | namespace mirror { | 
|  | class ClassLoader; | 
|  | class DexCache; | 
|  | class DexCachePointerArray; | 
|  | class DexCacheMethodHandlesTest_Open_Test; | 
|  | class DexCacheTest_Open_Test; | 
|  | class IfTable; | 
|  | class MethodHandle; | 
|  | class MethodHandlesLookup; | 
|  | class MethodType; | 
|  | template<class T> class ObjectArray; | 
|  | class StackTraceElement; | 
|  | }  // namespace mirror | 
|  |  | 
|  | namespace verifier { | 
|  | class VerifierDeps; | 
|  | } | 
|  |  | 
|  | class ClassVisitor { | 
|  | public: | 
|  | virtual ~ClassVisitor() {} | 
|  | // Return true to continue visiting. | 
|  | virtual bool operator()(ObjPtr<mirror::Class> klass) = 0; | 
|  | }; | 
|  |  | 
|  | template <typename Func> | 
|  | class ClassFuncVisitor final : public ClassVisitor { | 
|  | public: | 
|  | explicit ClassFuncVisitor(Func func) : func_(func) {} | 
|  | bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) { | 
|  | return func_(klass); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Func func_; | 
|  | }; | 
|  |  | 
|  | class ClassLoaderVisitor { | 
|  | public: | 
|  | virtual ~ClassLoaderVisitor() {} | 
|  | virtual void Visit(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) = 0; | 
|  | }; | 
|  |  | 
|  | template <typename Func> | 
|  | class ClassLoaderFuncVisitor final : public ClassLoaderVisitor { | 
|  | public: | 
|  | explicit ClassLoaderFuncVisitor(Func func) : func_(func) {} | 
|  | void Visit(ObjPtr<mirror::ClassLoader> cl) override REQUIRES_SHARED(Locks::mutator_lock_) { | 
|  | func_(cl); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Func func_; | 
|  | }; | 
|  |  | 
|  | class AllocatorVisitor { | 
|  | public: | 
|  | virtual ~AllocatorVisitor() {} | 
|  | // Return true to continue visiting. | 
|  | virtual bool Visit(LinearAlloc* alloc) | 
|  | REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) = 0; | 
|  | }; | 
|  |  | 
|  | class ClassLinker { | 
|  | public: | 
|  | static constexpr bool kAppImageMayContainStrings = true; | 
|  |  | 
|  | explicit ClassLinker(InternTable* intern_table, | 
|  | bool fast_class_not_found_exceptions = true); | 
|  | virtual ~ClassLinker(); | 
|  |  | 
|  | // Initialize class linker by bootstraping from dex files. | 
|  | bool InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path, | 
|  | std::string* error_msg) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Initialize class linker from one or more boot images. | 
|  | bool InitFromBootImage(std::string* error_msg) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Add boot class path dex files that were not included in the boot image. | 
|  | // ClassLinker takes ownership of these dex files. | 
|  | void AddExtraBootDexFiles(Thread* self, | 
|  | std::vector<std::unique_ptr<const DexFile>>&& additional_dex_files) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Add an image space to the class linker, may fix up classloader fields and dex cache fields. | 
|  | // The dex files that were newly opened for the space are placed in the out argument | 
|  | // out_dex_files. Returns true if the operation succeeded. | 
|  | // The space must be already added to the heap before calling AddImageSpace since we need to | 
|  | // properly handle read barriers and object marking. | 
|  | bool AddImageSpace(gc::space::ImageSpace* space, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | std::vector<std::unique_ptr<const DexFile>>* out_dex_files, | 
|  | std::string* error_msg) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | bool OpenImageDexFiles(gc::space::ImageSpace* space, | 
|  | std::vector<std::unique_ptr<const DexFile>>* out_dex_files, | 
|  | std::string* error_msg) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Finds a class by its descriptor, loading it if necessary. | 
|  | // If class_loader is null, searches boot_class_path_. | 
|  | ObjPtr<mirror::Class> FindClass(Thread* self, | 
|  | const char* descriptor, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Finds a class by its descriptor using the "system" class loader, ie by searching the | 
|  | // boot_class_path_. | 
|  | ObjPtr<mirror::Class> FindSystemClass(Thread* self, const char* descriptor) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_) { | 
|  | return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>()); | 
|  | } | 
|  |  | 
|  | // Finds the array class given for the element class. | 
|  | ObjPtr<mirror::Class> FindArrayClass(Thread* self, ObjPtr<mirror::Class> element_class) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Returns true if the class linker is initialized. | 
|  | bool IsInitialized() const { | 
|  | return init_done_; | 
|  | } | 
|  |  | 
|  | // Define a new a class based on a ClassDef from a DexFile | 
|  | ObjPtr<mirror::Class> DefineClass(Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | const DexFile& dex_file, | 
|  | const dex::ClassDef& dex_class_def) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Finds a class by its descriptor, returning null if it isn't wasn't loaded | 
|  | // by the given 'class_loader'. | 
|  | ObjPtr<mirror::Class> LookupClass(Thread* self, | 
|  | const char* descriptor, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Finds all the classes with the given descriptor, regardless of ClassLoader. | 
|  | void LookupClasses(const char* descriptor, std::vector<ObjPtr<mirror::Class>>& classes) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ObjPtr<mirror::Class> LookupPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::Class> FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_); | 
|  |  | 
|  | size_t NumLoadedClasses() | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a String with the given index from the DexFile associated with the given `referrer`, | 
|  | // storing the result in the DexCache. The `referrer` is used to identify the target DexCache | 
|  | // to use for resolution. | 
|  | ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, | 
|  | ArtField* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, | 
|  | ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a String with the given index from the DexFile associated with the given DexCache, | 
|  | // storing the result in the DexCache. | 
|  | ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, | 
|  | Handle<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Find a String with the given index from the DexFile associated with the given DexCache, | 
|  | // storing the result in the DexCache if found. Return null if not found. | 
|  | ObjPtr<mirror::String> LookupString(dex::StringIndex string_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a Type with the given index from the DexFile associated with the given `referrer`, | 
|  | // storing the result in the DexCache. The `referrer` is used to identify the target DexCache | 
|  | // and ClassLoader to use for resolution. | 
|  | ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  | ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtField* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  | ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Resolve a type with the given index from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The ClassLoader is used to search for | 
|  | // the type, since it may be referenced from but not contained within the DexFile. | 
|  | ObjPtr<mirror::Class> ResolveType(dex::TypeIndex type_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Look up a resolved type with the given index from the DexFile associated with the given | 
|  | // `referrer`, storing the result in the DexCache. The `referrer` is used to identify the | 
|  | // target DexCache and ClassLoader to use for lookup. | 
|  | ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, | 
|  | ObjPtr<mirror::Class> referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtField* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Look up a resolved type with the given index from the DexFile associated with the given | 
|  | // DexCache and ClassLoader. The ClassLoader is used to search for the type, since it may | 
|  | // be referenced from but not contained within the DexFile. | 
|  | ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Look up a resolved type with the given descriptor associated with the given ClassLoader. | 
|  | ObjPtr<mirror::Class> LookupResolvedType(const char* descriptor, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError | 
|  | // check and IllegalAccessError check should be performed even after a hit. | 
|  | enum class ResolveMode {  // private. | 
|  | kNoChecks, | 
|  | kCheckICCEAndIAE | 
|  | }; | 
|  |  | 
|  | // Look up a previously resolved method with the given index. | 
|  | ArtMethod* LookupResolvedMethod(uint32_t method_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Find a method with the given index from class `klass`, and update the dex cache. | 
|  | ArtMethod* FindResolvedMethod(ObjPtr<mirror::Class> klass, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader, | 
|  | uint32_t method_idx) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Find a method using the wrong lookup mechanism. If `klass` is an interface, | 
|  | // search for a class method. If it is a class, search for an interface method. | 
|  | // This is useful when throwing IncompatibleClassChangeError. | 
|  | ArtMethod* FindIncompatibleMethod(ObjPtr<mirror::Class> klass, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader, | 
|  | uint32_t method_idx) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a method with a given ID from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are | 
|  | // used as in ResolveType. What is unique is the method type argument which is used to | 
|  | // determine if this method is a direct, static, or virtual method. | 
|  | template <ResolveMode kResolveMode> | 
|  | ArtMethod* ResolveMethod(uint32_t method_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | ArtMethod* referrer, | 
|  | InvokeType type) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | template <InvokeType type, ResolveMode kResolveMode> | 
|  | ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | template <ResolveMode kResolveMode> | 
|  | ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  | ArtMethod* ResolveMethodWithoutInvokeType(uint32_t method_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | ArtField* LookupResolvedField(uint32_t field_idx, ArtMethod* referrer, bool is_static) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Resolve a field with a given ID from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader | 
|  | // are used as in ResolveType. What is unique is the is_static argument which is used | 
|  | // to determine if we are resolving a static or non-static field. | 
|  | ArtField* ResolveField(uint32_t field_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | bool is_static) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Resolve a field with a given ID from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader | 
|  | // are used as in ResolveType. No is_static argument is provided so that Java | 
|  | // field resolution semantics are followed. | 
|  | ArtField* ResolveFieldJLS(uint32_t field_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Find a field with a given ID from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The declaring class is assumed | 
|  | // to have been already resolved into `klass`. The `is_static` argument is used to | 
|  | // determine if we are resolving a static or non-static field. | 
|  | ArtField* FindResolvedField(ObjPtr<mirror::Class> klass, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader, | 
|  | uint32_t field_idx, | 
|  | bool is_static) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Find a field with a given ID from the DexFile associated with the given DexCache | 
|  | // and ClassLoader, storing the result in DexCache. The declaring class is assumed | 
|  | // to have been already resolved into `klass`. No is_static argument is provided | 
|  | // so that Java field resolution semantics are followed. | 
|  | ArtField* FindResolvedFieldJLS(ObjPtr<mirror::Class> klass, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader, | 
|  | uint32_t field_idx) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a method type with a given ID from the DexFile associated with a given DexCache | 
|  | // and ClassLoader, storing the result in the DexCache. | 
|  | ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self, | 
|  | dex::ProtoIndex proto_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self, | 
|  | dex::ProtoIndex proto_idx, | 
|  | ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Resolve a method handle with a given ID from the DexFile. The | 
|  | // result is not cached in the DexCache as the instance will only be | 
|  | // used once in most circumstances. | 
|  | ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self, | 
|  | uint32_t method_handle_idx, | 
|  | ArtMethod* referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns true on success, false if there's an exception pending. | 
|  | // can_run_clinit=false allows the compiler to attempt to init a class, | 
|  | // given the restriction that no <clinit> execution is possible. | 
|  | bool EnsureInitialized(Thread* self, | 
|  | Handle<mirror::Class> c, | 
|  | bool can_init_fields, | 
|  | bool can_init_parents) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Initializes classes that have instances in the image but that have | 
|  | // <clinit> methods so they could not be initialized by the compiler. | 
|  | void RunRootClinits(Thread* self) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Directly register an already existing dex cache. RegisterDexFile should be preferred since that | 
|  | // reduplicates DexCaches when possible. The DexCache given to this function must already be fully | 
|  | // initialized and not already registered. | 
|  | void RegisterExistingDexCache(ObjPtr<mirror::DexCache> cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::DexCache> RegisterDexFile(const DexFile& dex_file, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | const std::vector<const DexFile*>& GetBootClassPath() { | 
|  | return boot_class_path_; | 
|  | } | 
|  |  | 
|  | void VisitClasses(ClassVisitor* visitor) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Less efficient variant of VisitClasses that copies the class_table_ into secondary storage | 
|  | // so that it can visit individual classes without holding the doesn't hold the | 
|  | // Locks::classlinker_classes_lock_. As the Locks::classlinker_classes_lock_ isn't held this code | 
|  | // can race with insertion and deletion of classes while the visitor is being called. | 
|  | void VisitClassesWithoutClassesLock(ClassVisitor* visitor) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | void VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_, !Locks::trace_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | void VisitRoots(RootVisitor* visitor, VisitRootFlags flags) | 
|  | REQUIRES(!Locks::dex_lock_, !Locks::classlinker_classes_lock_, !Locks::trace_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | // Visits all dex-files accessible by any class-loader or the BCP. | 
|  | template<typename Visitor> | 
|  | void VisitKnownDexFiles(Thread* self, Visitor visitor) REQUIRES(Locks::mutator_lock_); | 
|  |  | 
|  | bool IsDexFileRegistered(Thread* self, const DexFile& dex_file) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::DexCache> FindDexCache(Thread* self, const DexFile& dex_file) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::DexCache> FindDexCache(Thread* self, const OatDexFile& oat_dex_file) | 
|  | REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ClassTable* FindClassTable(Thread* self, ObjPtr<mirror::DexCache> dex_cache) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | LengthPrefixedArray<ArtField>* AllocArtFieldArray(Thread* self, | 
|  | LinearAlloc* allocator, | 
|  | size_t length); | 
|  |  | 
|  | LengthPrefixedArray<ArtMethod>* AllocArtMethodArray(Thread* self, | 
|  | LinearAlloc* allocator, | 
|  | size_t length); | 
|  |  | 
|  | // Convenience AllocClass() overload that uses mirror::Class::InitializeClassVisitor | 
|  | // for the class initialization and uses the `java_lang_Class` from class roots | 
|  | // instead of an explicit argument. | 
|  | ObjPtr<mirror::Class> AllocClass(Thread* self, uint32_t class_size) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Setup the classloader, class def index, type idx so that we can insert this class in the class | 
|  | // table. | 
|  | void SetupClass(const DexFile& dex_file, | 
|  | const dex::ClassDef& dex_class_def, | 
|  | Handle<mirror::Class> klass, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void LoadClass(Thread* self, | 
|  | const DexFile& dex_file, | 
|  | const dex::ClassDef& dex_class_def, | 
|  | Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Link the class and place it into the class-table using the given descriptor. NB if the | 
|  | // descriptor is null the class will not be placed in any class-table. This is useful implementing | 
|  | // obsolete classes and should not be used otherwise. | 
|  | bool LinkClass(Thread* self, | 
|  | const char* descriptor, | 
|  | Handle<mirror::Class> klass, | 
|  | Handle<mirror::ObjectArray<mirror::Class>> interfaces, | 
|  | MutableHandle<mirror::Class>* h_new_class_out) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_); | 
|  |  | 
|  | ObjPtr<mirror::PointerArray> AllocPointerArray(Thread* self, size_t length) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> AllocStackTraceElementArray(Thread* self, | 
|  | size_t length) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | verifier::FailureKind VerifyClass( | 
|  | Thread* self, | 
|  | verifier::VerifierDeps* verifier_deps, | 
|  | Handle<mirror::Class> klass, | 
|  | verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  | bool VerifyClassUsingOatFile(Thread* self, | 
|  | const DexFile& dex_file, | 
|  | Handle<mirror::Class> klass, | 
|  | ClassStatus& oat_file_class_status) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  | void ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  | void ResolveMethodExceptionHandlerTypes(ArtMethod* klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | ObjPtr<mirror::Class> CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | jstring name, | 
|  | jobjectArray interfaces, | 
|  | jobject loader, | 
|  | jobjectArray methods, | 
|  | jobjectArray throws) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | pid_t GetClassesLockOwner();  // For SignalCatcher. | 
|  | pid_t GetDexLockOwner();  // For SignalCatcher. | 
|  |  | 
|  | // Is the given entry point quick code to run the resolution stub? | 
|  | bool IsQuickResolutionStub(const void* entry_point) const; | 
|  |  | 
|  | // Is the given entry point quick code to bridge into the interpreter? | 
|  | bool IsQuickToInterpreterBridge(const void* entry_point) const; | 
|  |  | 
|  | // Is the given entry point quick code to run the generic JNI stub? | 
|  | bool IsQuickGenericJniStub(const void* entry_point) const; | 
|  |  | 
|  | // Is the given entry point the JNI dlsym lookup stub? | 
|  | bool IsJniDlsymLookupStub(const void* entry_point) const; | 
|  |  | 
|  | // Is the given entry point the JNI dlsym lookup critical stub? | 
|  | bool IsJniDlsymLookupCriticalStub(const void* entry_point) const; | 
|  |  | 
|  | // Is the given entry point the nterp trampoline? | 
|  | bool IsNterpTrampoline(const void* entry_point) const { | 
|  | return nterp_trampoline_ == entry_point; | 
|  | } | 
|  |  | 
|  | const void* GetQuickToInterpreterBridgeTrampoline() const { | 
|  | return quick_to_interpreter_bridge_trampoline_; | 
|  | } | 
|  |  | 
|  | InternTable* GetInternTable() const { | 
|  | return intern_table_; | 
|  | } | 
|  |  | 
|  | // Set the entrypoints up for an obsolete method. | 
|  | void SetEntryPointsForObsoleteMethod(ArtMethod* method) const | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Attempts to insert a class into a class table.  Returns null if | 
|  | // the class was inserted, otherwise returns an existing class with | 
|  | // the same descriptor and ClassLoader. | 
|  | ObjPtr<mirror::Class> InsertClass(const char* descriptor, | 
|  | ObjPtr<mirror::Class> klass, | 
|  | size_t hash) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Add an oat file with .bss GC roots to be visited again at the end of GC | 
|  | // for collector types that need it. | 
|  | void WriteBarrierForBootOatFileBssRoots(const OatFile* oat_file) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> | 
|  | ObjPtr<mirror::ObjectArray<mirror::Class>> GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Move the class table to the pre-zygote table to reduce memory usage. This works by ensuring | 
|  | // that no more classes are ever added to the pre zygote table which makes it that the pages | 
|  | // always remain shared dirty instead of private dirty. | 
|  | void MoveClassTableToPreZygote() | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Creates a GlobalRef PathClassLoader or DelegateLastClassLoader (specified by loader_class) | 
|  | // that can be used to load classes from the given dex files. The parent of the class loader | 
|  | // will be set to `parent_loader`. If `parent_loader` is null the parent will be | 
|  | // the boot class loader. | 
|  | // If class_loader points to a different class than PathClassLoader or DelegateLastClassLoader | 
|  | // this method will abort. | 
|  | // Note: the objects are not completely set up. Do not use this outside of tests and the compiler. | 
|  | jobject CreateWellKnownClassLoader(Thread* self, | 
|  | const std::vector<const DexFile*>& dex_files, | 
|  | jclass loader_class, | 
|  | jobject parent_loader, | 
|  | jobject shared_libraries = nullptr, | 
|  | jobject shared_libraries_after = nullptr) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Calls CreateWellKnownClassLoader(self, | 
|  | //                                  dex_files, | 
|  | //                                  WellKnownClasses::dalvik_system_PathClassLoader, | 
|  | //                                  nullptr) | 
|  | jobject CreatePathClassLoader(Thread* self, const std::vector<const DexFile*>& dex_files) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Non-GlobalRef version of CreateWellKnownClassLoader | 
|  | ObjPtr<mirror::ClassLoader> CreateWellKnownClassLoader( | 
|  | Thread* self, | 
|  | const std::vector<const DexFile*>& dex_files, | 
|  | Handle<mirror::Class> loader_class, | 
|  | Handle<mirror::ClassLoader> parent_loader, | 
|  | Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries, | 
|  | Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_after) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | PointerSize GetImagePointerSize() const { | 
|  | return image_pointer_size_; | 
|  | } | 
|  |  | 
|  | // Clear the ArrayClass cache. This is necessary when cleaning up for the image, as the cache | 
|  | // entries are roots, but potentially not image classes. | 
|  | void DropFindArrayClassCache() REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Clean up class loaders, this needs to happen after JNI weak globals are cleared. | 
|  | void CleanupClassLoaders() | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Unlike GetOrCreateAllocatorForClassLoader, GetAllocatorForClassLoader asserts that the | 
|  | // allocator for this class loader is already created. | 
|  | LinearAlloc* GetAllocatorForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return the linear alloc for a class loader if it is already allocated, otherwise allocate and | 
|  | // set it. TODO: Consider using a lock other than classlinker_classes_lock_. | 
|  | LinearAlloc* GetOrCreateAllocatorForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // May be called with null class_loader due to legacy code. b/27954959 | 
|  | void InsertDexFileInToClassLoader(ObjPtr<mirror::Object> dex_file, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ArtMethod* AddMethodToConflictTable(ObjPtr<mirror::Class> klass, | 
|  | ArtMethod* conflict_method, | 
|  | ArtMethod* interface_method, | 
|  | ArtMethod* method) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Create a conflict table with a specified capacity. | 
|  | ImtConflictTable* CreateImtConflictTable(size_t count, LinearAlloc* linear_alloc); | 
|  |  | 
|  | // Static version for when the class linker is not yet created. | 
|  | static ImtConflictTable* CreateImtConflictTable(size_t count, | 
|  | LinearAlloc* linear_alloc, | 
|  | PointerSize pointer_size); | 
|  |  | 
|  |  | 
|  | // Create the IMT and conflict tables for a class. | 
|  | void FillIMTAndConflictTables(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Visit all of the class tables. This is used by dex2oat to allow pruning dex caches. | 
|  | template <class Visitor> | 
|  | void VisitClassTables(const Visitor& visitor) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Visit all of the allocators that belong to classloaders except boot classloader. | 
|  | // This is used by 616-cha-unloading test to confirm memory reuse. | 
|  | void VisitAllocators(AllocatorVisitor* visitor) const | 
|  | REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_); | 
|  |  | 
|  | // Throw the class initialization failure recorded when first trying to initialize the given | 
|  | // class. | 
|  | void ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, | 
|  | bool wrap_in_no_class_def = false, | 
|  | bool log = false) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Get the actual holding class for a copied method. Pretty slow, don't call often. | 
|  | ObjPtr<mirror::Class> GetHoldingClassOfCopiedMethod(ArtMethod* method) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns null if not found. | 
|  | // This returns a pointer to the class-table, without requiring any locking - including the | 
|  | // boot class-table. It is the caller's responsibility to access this under lock, if required. | 
|  | ClassTable* ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | NO_THREAD_SAFETY_ANALYSIS; | 
|  |  | 
|  | void AppendToBootClassPath(Thread* self, const DexFile* dex_file) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | void AppendToBootClassPath(const DexFile* dex_file, ObjPtr<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Visit all of the class loaders in the class linker. | 
|  | void VisitClassLoaders(ClassLoaderVisitor* visitor) const | 
|  | REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_); | 
|  |  | 
|  | // Checks that a class and its superclass from another class loader have the same virtual methods. | 
|  | bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ClassHierarchyAnalysis* GetClassHierarchyAnalysis() { | 
|  | return cha_.get(); | 
|  | } | 
|  |  | 
|  | void MakeInitializedClassesVisiblyInitialized(Thread* self, bool wait); | 
|  |  | 
|  | // Registers the native method and returns the new entry point. NB The returned entry point | 
|  | // might be different from the native_method argument if some MethodCallback modifies it. | 
|  | const void* RegisterNative(Thread* self, ArtMethod* method, const void* native_method) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Unregister native code for a method. | 
|  | void UnregisterNative(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Get the registered native method entrypoint, if any, otherwise null. | 
|  | const void* GetRegisteredNative(Thread* self, ArtMethod* method) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!critical_native_code_with_clinit_check_lock_); | 
|  |  | 
|  | struct DexCacheData { | 
|  | // Construct an invalid data object. | 
|  | DexCacheData() : weak_root(nullptr), class_table(nullptr) { | 
|  | static std::atomic_uint64_t s_registration_count(0); | 
|  | registration_index = s_registration_count.fetch_add(1, std::memory_order_seq_cst); | 
|  | } | 
|  | DexCacheData(DexCacheData&&) = default; | 
|  |  | 
|  | // Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may | 
|  | // not work properly. | 
|  | jweak weak_root; | 
|  | // Identify the associated class loader's class table. This is used to make sure that | 
|  | // the Java call to native DexCache.setResolvedType() inserts the resolved type in that | 
|  | // class table. It is also used to make sure we don't register the same dex cache with | 
|  | // multiple class loaders. | 
|  | ClassTable* class_table; | 
|  | // Monotonically increasing integer which records the order in which DexFiles were registered. | 
|  | // Used only to preserve determinism when creating compiled image. | 
|  | uint64_t registration_index; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(DexCacheData); | 
|  | }; | 
|  |  | 
|  | // Forces a class to be marked as initialized without actually running initializers. Should only | 
|  | // be used by plugin code when creating new classes directly. | 
|  | void ForceClassInitialized(Thread* self, Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Verifies if the method is accesible according to the SdkChecker (if installed). | 
|  | virtual bool DenyAccessBasedOnPublicSdk(ArtMethod* art_method) const | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | // Verifies if the field is accesible according to the SdkChecker (if installed). | 
|  | virtual bool DenyAccessBasedOnPublicSdk(ArtField* art_field) const | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | // Verifies if the descriptor is accesible according to the SdkChecker (if installed). | 
|  | virtual bool DenyAccessBasedOnPublicSdk(const char* type_descriptor) const; | 
|  | // Enable or disable public sdk checks. | 
|  | virtual void SetEnablePublicSdkChecks(bool enabled); | 
|  |  | 
|  | protected: | 
|  | virtual bool InitializeClass(Thread* self, | 
|  | Handle<mirror::Class> klass, | 
|  | bool can_run_clinit, | 
|  | bool can_init_parents) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | virtual verifier::FailureKind PerformClassVerification(Thread* self, | 
|  | verifier::VerifierDeps* verifier_deps, | 
|  | Handle<mirror::Class> klass, | 
|  | verifier::HardFailLogMode log_level, | 
|  | std::string* error_msg) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | virtual bool CanAllocClass() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | class LinkFieldsHelper; | 
|  | template <PointerSize kPointerSize> | 
|  | class LinkMethodsHelper; | 
|  | class VisiblyInitializedCallback; | 
|  |  | 
|  | struct ClassLoaderData { | 
|  | jweak weak_root;  // Weak root to enable class unloading. | 
|  | ClassTable* class_table; | 
|  | LinearAlloc* allocator; | 
|  | }; | 
|  |  | 
|  | void VisiblyInitializedCallbackDone(Thread* self, VisiblyInitializedCallback* callback); | 
|  | VisiblyInitializedCallback* MarkClassInitialized(Thread* self, Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Ensures that the supertype of 'klass' ('supertype') is verified. Returns false and throws | 
|  | // appropriate exceptions if verification failed hard. Returns true for successful verification or | 
|  | // soft-failures. | 
|  | bool AttemptSupertypeVerification(Thread* self, | 
|  | verifier::VerifierDeps* verifier_deps, | 
|  | Handle<mirror::Class> klass, | 
|  | Handle<mirror::Class> supertype) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void DeleteClassLoader(Thread* self, const ClassLoaderData& data, bool cleanup_cha) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void VisitClassesInternal(ClassVisitor* visitor) | 
|  | REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_); | 
|  |  | 
|  | // Returns the number of zygote and image classes. | 
|  | size_t NumZygoteClasses() const | 
|  | REQUIRES(Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Returns the number of non zygote nor image classes. | 
|  | size_t NumNonZygoteClasses() const | 
|  | REQUIRES(Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void FinishInit(Thread* self) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // If we do not allow moving classes (`art::kMovingClass` is false) or if | 
|  | // parameter `kMovable` is false (or both), the class object is allocated in | 
|  | // the non-moving space. | 
|  | template <bool kMovable = true, class PreFenceVisitor> | 
|  | ObjPtr<mirror::Class> AllocClass(Thread* self, | 
|  | ObjPtr<mirror::Class> java_lang_Class, | 
|  | uint32_t class_size, | 
|  | const PreFenceVisitor& pre_fence_visitor) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Convenience AllocClass() overload that uses mirror::Class::InitializeClassVisitor | 
|  | // for the class initialization. | 
|  | template <bool kMovable = true> | 
|  | ObjPtr<mirror::Class> AllocClass(Thread* self, | 
|  | ObjPtr<mirror::Class> java_lang_Class, | 
|  | uint32_t class_size) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Allocate a primitive array class and store it in appropriate class root. | 
|  | void AllocPrimitiveArrayClass(Thread* self, | 
|  | ClassRoot primitive_root, | 
|  | ClassRoot array_root) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Finish setup of an array class. | 
|  | void FinishArrayClassSetup(ObjPtr<mirror::Class> array_class) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Finish setup of a core array class (Object[], Class[], String[] and | 
|  | // primitive arrays) and insert it into the class table. | 
|  | void FinishCoreArrayClassSetup(ClassRoot array_root) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | ObjPtr<mirror::DexCache> AllocDexCache(Thread* self, const DexFile& dex_file) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Used for tests and AppendToBootClassPath. | 
|  | ObjPtr<mirror::DexCache> AllocAndInitializeDexCache(Thread* self, | 
|  | const DexFile& dex_file, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | // Create a primitive class and store it in the appropriate class root. | 
|  | void CreatePrimitiveClass(Thread* self, Primitive::Type type, ClassRoot primitive_root) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Roles::uninterruptible_); | 
|  |  | 
|  | ObjPtr<mirror::Class> CreateArrayClass(Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Precomputes size needed for Class, in the case of a non-temporary class this size must be | 
|  | // sufficient to hold all static fields. | 
|  | uint32_t SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, | 
|  | const dex::ClassDef& dex_class_def); | 
|  |  | 
|  | void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void LoadMethod(const DexFile& dex_file, | 
|  | const ClassAccessor::Method& method, | 
|  | ObjPtr<mirror::Class> klass, | 
|  | ArtMethod* dst) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Finds a class in a Path- or DexClassLoader, loading it if necessary without using JNI. Hash | 
|  | // function is supposed to be ComputeModifiedUtf8Hash(descriptor). Returns true if the | 
|  | // class-loader chain could be handled, false otherwise, i.e., a non-supported class-loader | 
|  | // was encountered while walking the parent chain (currently only BootClassLoader and | 
|  | // PathClassLoader are supported). | 
|  | bool FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | bool FindClassInSharedLibraries(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | bool FindClassInSharedLibrariesHelper(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | ArtField* field, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | bool FindClassInSharedLibrariesAfter(ScopedObjectAccessAlreadyRunnable& soa, | 
|  | Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Finds the class in the classpath of the given class loader. It only searches the class loader | 
|  | // dex files and does not recurse into its parent. | 
|  | // The method checks that the provided class loader is either a PathClassLoader or a | 
|  | // DexClassLoader. | 
|  | // If the class is found the method updates `result`. | 
|  | // The method always returns true, to notify to the caller a | 
|  | // BaseDexClassLoader has a known lookup. | 
|  | bool FindClassInBaseDexClassLoaderClassPath( | 
|  | ScopedObjectAccessAlreadyRunnable& soa, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | Handle<mirror::ClassLoader> class_loader, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Finds the class in the boot class loader. | 
|  | // If the class is found the method updates `result`. | 
|  | // The method always returns true, to notify to the caller the | 
|  | // boot class loader has a known lookup. | 
|  | bool FindClassInBootClassLoaderClassPath(Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | /*out*/ ObjPtr<mirror::Class>* result) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | // Implementation of LookupResolvedType() called when the type was not found in the dex cache. | 
|  | ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx, | 
|  | ObjPtr<mirror::Class> referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::Class> DoLookupResolvedType(dex::TypeIndex type_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Implementation of ResolveString() called when the string was not found in the dex cache. | 
|  | ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, | 
|  | Handle<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Implementation of LookupString() called when the string was not found in the dex cache. | 
|  | ObjPtr<mirror::String> DoLookupString(dex::StringIndex string_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Implementation of ResolveType() called when the type was not found in the dex cache. May be | 
|  | // used with ArtField*, ArtMethod* or ObjPtr<Class>. | 
|  | template <typename RefType> | 
|  | ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx, RefType referrer) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  | ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx, | 
|  | Handle<mirror::DexCache> dex_cache, | 
|  | Handle<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); | 
|  |  | 
|  | // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded | 
|  | // by the given 'class_loader'. Uses the provided hash for the descriptor. | 
|  | ObjPtr<mirror::Class> LookupClass(Thread* self, | 
|  | const char* descriptor, | 
|  | size_t hash, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Find a field by its field index. | 
|  | ArtField* LookupResolvedField(uint32_t field_idx, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader, | 
|  | bool is_static) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void RegisterDexFileLocked(const DexFile& dex_file, | 
|  | ObjPtr<mirror::DexCache> dex_cache, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES(Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | const DexCacheData* FindDexCacheDataLocked(const DexFile& dex_file) | 
|  | REQUIRES_SHARED(Locks::dex_lock_); | 
|  | const DexCacheData* FindDexCacheDataLocked(const OatDexFile& oat_dex_file) | 
|  | REQUIRES_SHARED(Locks::dex_lock_); | 
|  | static ObjPtr<mirror::DexCache> DecodeDexCacheLocked(Thread* self, const DexCacheData* data) | 
|  | REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_); | 
|  | bool IsSameClassLoader(ObjPtr<mirror::DexCache> dex_cache, | 
|  | const DexCacheData* data, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_); | 
|  |  | 
|  | bool InitializeDefaultInterfaceRecursive(Thread* self, | 
|  | Handle<mirror::Class> klass, | 
|  | bool can_run_clinit, | 
|  | bool can_init_parents) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | bool WaitForInitializeClass(Handle<mirror::Class> klass, | 
|  | Thread* self, | 
|  | ObjectLock<mirror::Class>& lock); | 
|  |  | 
|  | bool IsSameDescriptorInDifferentClassContexts(Thread* self, | 
|  | const char* descriptor, | 
|  | Handle<mirror::ClassLoader> class_loader1, | 
|  | Handle<mirror::ClassLoader> class_loader2) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, | 
|  | ArtMethod* method, | 
|  | ObjPtr<mirror::Class> klass1, | 
|  | ObjPtr<mirror::Class> klass2) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | bool LinkSuperClass(Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | bool LinkMethods(Thread* self, | 
|  | Handle<mirror::Class> klass, | 
|  | Handle<mirror::ObjectArray<mirror::Class>> interfaces, | 
|  | bool* out_new_conflict, | 
|  | ArtMethod** out_imt) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ObjPtr<mirror::MethodHandle> ResolveMethodHandleForField( | 
|  | Thread* self, | 
|  | const dex::MethodHandleItem& method_handle, | 
|  | ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ObjPtr<mirror::MethodHandle> ResolveMethodHandleForMethod( | 
|  | Thread* self, | 
|  | const dex::MethodHandleItem& method_handle, | 
|  | ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | bool LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | bool LinkInstanceFields(Thread* self, Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void CheckProxyConstructor(ArtMethod* constructor) const | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | void CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | size_t GetDexCacheCount() REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) { | 
|  | return dex_caches_.size(); | 
|  | } | 
|  | const std::unordered_map<const DexFile*, DexCacheData>& GetDexCachesData() | 
|  | REQUIRES_SHARED(Locks::mutator_lock_, Locks::dex_lock_) { | 
|  | return dex_caches_; | 
|  | } | 
|  |  | 
|  | void CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Register a class loader and create its class table and allocator. Should not be called if | 
|  | // these are already created. | 
|  | void RegisterClassLoader(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // Insert a new class table if not found. | 
|  | ClassTable* InsertClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // EnsureResolved is called to make sure that a class in the class_table_ has been resolved | 
|  | // before returning it to the caller. Its the responsibility of the thread that placed the class | 
|  | // in the table to make it resolved. The thread doing resolution must notify on the class' lock | 
|  | // when resolution has occurred. This happens in mirror::Class::SetStatus. As resolution may | 
|  | // retire a class, the version of the class in the table is returned and this may differ from | 
|  | // the class passed in. | 
|  | ObjPtr<mirror::Class> EnsureResolved(Thread* self, | 
|  | const char* descriptor, | 
|  | ObjPtr<mirror::Class> klass) | 
|  | WARN_UNUSED | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::dex_lock_); | 
|  |  | 
|  | void FixupTemporaryDeclaringClass(ObjPtr<mirror::Class> temp_class, | 
|  | ObjPtr<mirror::Class> new_class) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void SetClassRoot(ClassRoot class_root, ObjPtr<mirror::Class> klass) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Return the quick generic JNI stub for testing. | 
|  | const void* GetRuntimeQuickGenericJniStub() const; | 
|  |  | 
|  | bool CanWeInitializeClass(ObjPtr<mirror::Class> klass, | 
|  | bool can_init_statics, | 
|  | bool can_init_parents) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void UpdateClassMethods(ObjPtr<mirror::Class> klass, | 
|  | LengthPrefixedArray<ArtMethod>* new_methods) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) | 
|  | REQUIRES(!Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // Check that c1 == FindSystemClass(self, descriptor). Abort with class dumps otherwise. | 
|  | void CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor) | 
|  | REQUIRES(!Locks::dex_lock_) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Sets imt_ref appropriately for LinkInterfaceMethods. | 
|  | // If there is no method in the imt location of imt_ref it will store the given method there. | 
|  | // Otherwise it will set the conflict method which will figure out which method to use during | 
|  | // runtime. | 
|  | void SetIMTRef(ArtMethod* unimplemented_method, | 
|  | ArtMethod* imt_conflict_method, | 
|  | ArtMethod* current_method, | 
|  | /*out*/bool* new_conflict, | 
|  | /*out*/ArtMethod** imt_ref) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | void FillIMTFromIfTable(ObjPtr<mirror::IfTable> if_table, | 
|  | ArtMethod* unimplemented_method, | 
|  | ArtMethod* imt_conflict_method, | 
|  | ObjPtr<mirror::Class> klass, | 
|  | bool create_conflict_tables, | 
|  | bool ignore_copied_methods, | 
|  | /*out*/bool* new_conflict, | 
|  | /*out*/ArtMethod** imt) REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | // Check invoke type against the referenced class. Throws IncompatibleClassChangeError | 
|  | // (if `kThrowOnError`) and returns true on mismatch (kInterface on a non-interface class, | 
|  | // kVirtual on interface, kDefault on interface for dex files not supporting default methods), | 
|  | // otherwise returns false. | 
|  | template <bool kThrowOnError, typename ClassGetter> | 
|  | static bool CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache, | 
|  | InvokeType type, | 
|  | ClassGetter class_getter) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  | // Helper that feeds the above function with `ClassGetter` doing `LookupResolvedType()`. | 
|  | template <bool kThrow> | 
|  | bool CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache, | 
|  | InvokeType type, | 
|  | uint32_t method_idx, | 
|  | ObjPtr<mirror::ClassLoader> class_loader) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | ObjPtr<mirror::IfTable> GetArrayIfTable() REQUIRES_SHARED(Locks::mutator_lock_); | 
|  |  | 
|  | std::vector<const DexFile*> boot_class_path_; | 
|  | std::vector<std::unique_ptr<const DexFile>> boot_dex_files_; | 
|  |  | 
|  | // JNI weak globals and side data to allow dex caches to get unloaded. We lazily delete weak | 
|  | // globals when we register new dex files. | 
|  | std::unordered_map<const DexFile*, DexCacheData> dex_caches_ GUARDED_BY(Locks::dex_lock_); | 
|  |  | 
|  | // This contains the class loaders which have class tables. It is populated by | 
|  | // InsertClassTableForClassLoader. | 
|  | std::list<ClassLoaderData> class_loaders_ | 
|  | GUARDED_BY(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // Boot class path table. Since the class loader for this is null. | 
|  | std::unique_ptr<ClassTable> boot_class_table_ GUARDED_BY(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // New class roots, only used by CMS since the GC needs to mark these in the pause. | 
|  | std::vector<GcRoot<mirror::Class>> new_class_roots_ GUARDED_BY(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // Boot image oat files with new .bss GC roots to be visited in the pause by CMS. | 
|  | std::vector<const OatFile*> new_bss_roots_boot_oat_files_ | 
|  | GUARDED_BY(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | // Number of times we've searched dex caches for a class. After a certain number of misses we move | 
|  | // the classes into the class_table_ to avoid dex cache based searches. | 
|  | Atomic<uint32_t> failed_dex_cache_class_lookups_; | 
|  |  | 
|  | // Well known mirror::Class roots. | 
|  | GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_; | 
|  |  | 
|  | // Method hashes for virtual methods from java.lang.Object used | 
|  | // to avoid recalculating them for each class we link. | 
|  | uint32_t object_virtual_method_hashes_[mirror::Object::kVTableLength]; | 
|  |  | 
|  | // A cache of the last FindArrayClass results. The cache serves to avoid creating array class | 
|  | // descriptors for the sake of performing FindClass. | 
|  | static constexpr size_t kFindArrayCacheSize = 16; | 
|  | GcRoot<mirror::Class> find_array_class_cache_[kFindArrayCacheSize]; | 
|  | size_t find_array_class_cache_next_victim_; | 
|  |  | 
|  | bool init_done_; | 
|  | bool log_new_roots_ GUARDED_BY(Locks::classlinker_classes_lock_); | 
|  |  | 
|  | InternTable* intern_table_; | 
|  |  | 
|  | const bool fast_class_not_found_exceptions_; | 
|  |  | 
|  | // Trampolines within the image the bounce to runtime entrypoints. Done so that there is a single | 
|  | // patch point within the image. TODO: make these proper relocations. | 
|  | const void* jni_dlsym_lookup_trampoline_; | 
|  | const void* jni_dlsym_lookup_critical_trampoline_; | 
|  | const void* quick_resolution_trampoline_; | 
|  | const void* quick_imt_conflict_trampoline_; | 
|  | const void* quick_generic_jni_trampoline_; | 
|  | const void* quick_to_interpreter_bridge_trampoline_; | 
|  | const void* nterp_trampoline_; | 
|  |  | 
|  | // Image pointer size. | 
|  | PointerSize image_pointer_size_; | 
|  |  | 
|  | // Classes to transition from ClassStatus::kInitialized to ClassStatus::kVisiblyInitialized. | 
|  | Mutex visibly_initialized_callback_lock_; | 
|  | std::unique_ptr<VisiblyInitializedCallback> visibly_initialized_callback_ | 
|  | GUARDED_BY(visibly_initialized_callback_lock_); | 
|  | IntrusiveForwardList<VisiblyInitializedCallback> running_visibly_initialized_callbacks_ | 
|  | GUARDED_BY(visibly_initialized_callback_lock_); | 
|  |  | 
|  | // Registered native code for @CriticalNative methods of classes that are not visibly | 
|  | // initialized. These code pointers cannot be stored in ArtMethod as that would risk | 
|  | // skipping the class initialization check for direct calls from compiled code. | 
|  | Mutex critical_native_code_with_clinit_check_lock_; | 
|  | std::map<ArtMethod*, void*> critical_native_code_with_clinit_check_ | 
|  | GUARDED_BY(critical_native_code_with_clinit_check_lock_); | 
|  |  | 
|  | std::unique_ptr<ClassHierarchyAnalysis> cha_; | 
|  |  | 
|  | class FindVirtualMethodHolderVisitor; | 
|  |  | 
|  | friend class AppImageLoadingHelper; | 
|  | friend class ImageDumper;  // for DexLock | 
|  | friend struct linker::CompilationHelper;  // For Compile in ImageTest. | 
|  | friend class linker::ImageWriter;  // for GetClassRoots | 
|  | friend class JniCompilerTest;  // for GetRuntimeQuickGenericJniStub | 
|  | friend class JniInternalTest;  // for GetRuntimeQuickGenericJniStub | 
|  | friend class VMClassLoader;  // for LookupClass and FindClassInBaseDexClassLoader. | 
|  | ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for DexLock, and RegisterDexFileLocked | 
|  | ART_FRIEND_TEST(mirror::DexCacheMethodHandlesTest, Open);  // for AllocDexCache | 
|  | ART_FRIEND_TEST(mirror::DexCacheTest, Open);  // for AllocDexCache | 
|  | DISALLOW_COPY_AND_ASSIGN(ClassLinker); | 
|  | }; | 
|  |  | 
|  | class ClassLoadCallback { | 
|  | public: | 
|  | virtual ~ClassLoadCallback() {} | 
|  |  | 
|  | // Called immediately before beginning class-definition and immediately before returning from it. | 
|  | virtual void BeginDefineClass() REQUIRES_SHARED(Locks::mutator_lock_) {} | 
|  | virtual void EndDefineClass() REQUIRES_SHARED(Locks::mutator_lock_) {} | 
|  |  | 
|  | // If set we will replace initial_class_def & initial_dex_file with the final versions. The | 
|  | // callback author is responsible for ensuring these are allocated in such a way they can be | 
|  | // cleaned up if another transformation occurs. Note that both must be set or null/unchanged on | 
|  | // return. | 
|  | // Note: the class may be temporary, in which case a following ClassPrepare event will be a | 
|  | //       different object. It is the listener's responsibility to handle this. | 
|  | // Note: This callback is rarely useful so a default implementation has been given that does | 
|  | //       nothing. | 
|  | virtual void ClassPreDefine(const char* descriptor ATTRIBUTE_UNUSED, | 
|  | Handle<mirror::Class> klass ATTRIBUTE_UNUSED, | 
|  | Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED, | 
|  | const DexFile& initial_dex_file ATTRIBUTE_UNUSED, | 
|  | const dex::ClassDef& initial_class_def ATTRIBUTE_UNUSED, | 
|  | /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED, | 
|  | /*out*/dex::ClassDef const** final_class_def ATTRIBUTE_UNUSED) | 
|  | REQUIRES_SHARED(Locks::mutator_lock_) {} | 
|  |  | 
|  | // A class has been loaded. | 
|  | // Note: the class may be temporary, in which case a following ClassPrepare event will be a | 
|  | //       different object. It is the listener's responsibility to handle this. | 
|  | virtual void ClassLoad(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) = 0; | 
|  |  | 
|  | // A class has been prepared, i.e., resolved. As the ClassLoad event might have been for a | 
|  | // temporary class, provide both the former and the current class. | 
|  | virtual void ClassPrepare(Handle<mirror::Class> temp_klass, | 
|  | Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) = 0; | 
|  | }; | 
|  |  | 
|  | }  // namespace art | 
|  |  | 
|  | #endif  // ART_RUNTIME_CLASS_LINKER_H_ |