diff options
Diffstat (limited to 'runtime/class_linker.h')
| -rw-r--r-- | runtime/class_linker.h | 193 |
1 files changed, 155 insertions, 38 deletions
diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 73f9d4b864..29aac312c1 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -115,12 +115,15 @@ class ClassLinker { ~ClassLinker(); // Initialize class linker by bootstraping from dex files. - void InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path) + bool InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path, + std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); // Initialize class linker from one or more images. - void InitFromImage() SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + bool InitFromImage(std::string* error_msg) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. @@ -487,10 +490,17 @@ class ClassLinker { return class_roots; } - // Move all of the image classes into the class table for faster lookups. - void MoveImageClassesToClassTable() + // Move all of the boot image classes into the class table for faster lookups. + void AddBootImageClassesToClassTable() + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + + // Add image classes to the class table. + void AddImageClassesToClassTable(gc::space::ImageSpace* image_space, + mirror::ClassLoader* class_loader) REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(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. @@ -504,7 +514,10 @@ class ClassLinker { // Creates a GlobalRef PathClassLoader that can be used to load classes from the given dex files. // Note: the objects are not completely set up. Do not use this outside of tests and the compiler. - jobject CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files) + // If parent_loader is null then we use the boot class loader. + jobject CreatePathClassLoader(Thread* self, + std::vector<const DexFile*>& dex_files, + jobject parent_loader) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); @@ -544,6 +557,17 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + struct DexCacheData { + // Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may + // not work properly. + jweak weak_root; + // The following two fields are caches to the DexCache's fields and here to avoid unnecessary + // jweak decode that triggers read barriers (and mark them alive unnecessarily and mess with + // class unloading.) + const DexFile* dex_file; + GcRoot<mirror::Class>* resolved_types; + }; + private: struct ClassLoaderData { jweak weak_root; // Weak root to enable class unloading. @@ -551,6 +575,15 @@ class ClassLinker { LinearAlloc* allocator; }; + // 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, + Handle<mirror::Class> klass, + Handle<mirror::Class> supertype) + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + static void DeleteClassLoader(Thread* self, const ClassLoaderData& data) REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); @@ -572,7 +605,7 @@ class ClassLinker { SHARED_REQUIRES(Locks::mutator_lock_); void FinishInit(Thread* self) - SHARED_REQUIRES(Locks::mutator_lock_) + SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); // For early bootstrapping by Init @@ -712,6 +745,83 @@ class ClassLinker { ArtMethod** out_imt) SHARED_REQUIRES(Locks::mutator_lock_); + // Does anything needed to make sure that the compiler will not generate a direct invoke to this + // method. Should only be called on non-invokable methods. + void EnsureThrowsInvocationError(ArtMethod* method) + SHARED_REQUIRES(Locks::mutator_lock_); + + // A wrapper class representing the result of a method translation used for linking methods and + // updating superclass default methods. For each method in a classes vtable there are 4 states it + // could be in: + // 1) No translation is necessary. In this case there is no MethodTranslation object for it. This + // is the standard case and is true when the method is not overridable by a default method, + // the class defines a concrete implementation of the method, the default method implementation + // remains the same, or an abstract method stayed abstract. + // 2) The method must be translated to a different default method. We note this with + // CreateTranslatedMethod. + // 3) The method must be replaced with a conflict method. This happens when a superclass + // implements an interface with a default method and this class implements an unrelated + // interface that also defines that default method. We note this with CreateConflictingMethod. + // 4) The method must be replaced with an abstract miranda method. This happens when a superclass + // implements an interface with a default method and this class implements a subinterface of + // the superclass's interface which declares the default method abstract. We note this with + // CreateAbstractMethod. + // + // When a method translation is unnecessary (case #1), we don't put it into the + // default_translation maps. So an instance of MethodTranslation must be in one of #2-#4. + class MethodTranslation { + public: + // This slot must become a default conflict method. + static MethodTranslation CreateConflictingMethod() { + return MethodTranslation(Type::kConflict, /*translation*/nullptr); + } + + // This slot must become an abstract method. + static MethodTranslation CreateAbstractMethod() { + return MethodTranslation(Type::kAbstract, /*translation*/nullptr); + } + + // Use the given method as the current value for this vtable slot during translation. + static MethodTranslation CreateTranslatedMethod(ArtMethod* new_method) { + return MethodTranslation(Type::kTranslation, new_method); + } + + // Returns true if this is a method that must become a conflict method. + bool IsInConflict() const { + return type_ == Type::kConflict; + } + + // Returns true if this is a method that must become an abstract method. + bool IsAbstract() const { + return type_ == Type::kAbstract; + } + + // Returns true if this is a method that must become a different method. + bool IsTranslation() const { + return type_ == Type::kTranslation; + } + + // Get the translated version of this method. + ArtMethod* GetTranslation() const { + DCHECK(IsTranslation()); + DCHECK(translation_ != nullptr); + return translation_; + } + + private: + enum class Type { + kTranslation, + kConflict, + kAbstract, + }; + + MethodTranslation(Type type, ArtMethod* translation) + : translation_(translation), type_(type) {} + + ArtMethod* const translation_; + const Type type_; + }; + // Links the virtual methods for the given class and records any default methods that will need to // be updated later. // @@ -728,9 +838,10 @@ class ClassLinker { // scan, we therefore store the vtable index's that might need to be // updated with the method they will turn into. // TODO This whole default_translations thing is very dirty. There should be a better way. - bool LinkVirtualMethods(Thread* self, - Handle<mirror::Class> klass, - /*out*/std::unordered_map<size_t, ArtMethod*>* default_translations) + bool LinkVirtualMethods( + Thread* self, + Handle<mirror::Class> klass, + /*out*/std::unordered_map<size_t, MethodTranslation>* default_translations) SHARED_REQUIRES(Locks::mutator_lock_); // Sets up the interface lookup table (IFTable) in the correct order to allow searching for @@ -740,6 +851,13 @@ class ClassLinker { Handle<mirror::ObjectArray<mirror::Class>> interfaces) SHARED_REQUIRES(Locks::mutator_lock_); + + enum class DefaultMethodSearchResult { + kDefaultFound, + kAbstractFound, + kDefaultConflict + }; + // Find the default method implementation for 'interface_method' in 'klass', if one exists. // // Arguments: @@ -747,31 +865,31 @@ class ClassLinker { // * target_method - The method we are trying to find a default implementation for. // * klass - The class we are searching for a definition of target_method. // * out_default_method - The pointer we will store the found default method to on success. - // * icce_message - A string we will store an appropriate IncompatibleClassChangeError message - // into in case of failure. Note we must do it this way since we do not know - // whether we can allocate the exception object, which could cause us to go to - // sleep. // // Return value: - // * True - There were no conflicting method implementations found in the class while searching - // for target_method. The default method implementation is stored into out_default_method - // if it was found. Otherwise *out_default_method will be set to nullptr. - // * False - Conflicting method implementations were found when searching for target_method. The - // value of *out_default_method is undefined and *icce_message is a string that should - // be used to create an IncompatibleClassChangeError as soon as possible. - bool FindDefaultMethodImplementation(Thread* self, - ArtMethod* target_method, - Handle<mirror::Class> klass, - /*out*/ArtMethod** out_default_method, - /*out*/std::string* icce_message) const + // * kDefaultFound - There were no conflicting method implementations found in the class while + // searching for target_method. The default method implementation is stored into + // out_default_method. + // * kAbstractFound - There were no conflicting method implementations found in the class while + // searching for target_method but no default implementation was found either. + // out_default_method is set to null and the method should be considered not + // implemented. + // * kDefaultConflict - Conflicting method implementations were found when searching for + // target_method. The value of *out_default_method is null. + DefaultMethodSearchResult FindDefaultMethodImplementation( + Thread* self, + ArtMethod* target_method, + Handle<mirror::Class> klass, + /*out*/ArtMethod** out_default_method) const SHARED_REQUIRES(Locks::mutator_lock_); // Sets the imt entries and fixes up the vtable for the given class by linking all the interface // methods. See LinkVirtualMethods for an explanation of what default_translations is. - bool LinkInterfaceMethods(Thread* self, - Handle<mirror::Class> klass, - const std::unordered_map<size_t, ArtMethod*>& default_translations, - ArtMethod** out_imt) + bool LinkInterfaceMethods( + Thread* self, + Handle<mirror::Class> klass, + const std::unordered_map<size_t, MethodTranslation>& default_translations, + ArtMethod** out_imt) SHARED_REQUIRES(Locks::mutator_lock_); bool LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) @@ -801,7 +919,8 @@ class ClassLinker { size_t GetDexCacheCount() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) { return dex_caches_.size(); } - const std::list<jweak>& GetDexCaches() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) { + const std::list<DexCacheData>& GetDexCachesData() + SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) { return dex_caches_; } @@ -815,7 +934,7 @@ class ClassLinker { void EnsurePreverifiedMethods(Handle<mirror::Class> c) SHARED_REQUIRES(Locks::mutator_lock_); - mirror::Class* LookupClassFromImage(const char* descriptor) + mirror::Class* LookupClassFromBootImage(const char* descriptor) SHARED_REQUIRES(Locks::mutator_lock_); // Returns null if not found. @@ -848,9 +967,7 @@ class ClassLinker { // Throw the class initialization failure recorded when first trying to initialize the given // class. - // Note: Currently we only store the descriptor, so we cannot throw the exact throwable, only - // a recreation with a custom string. - void ThrowEarlierClassFailure(mirror::Class* c) + void ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def = false) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); @@ -866,9 +983,9 @@ class ClassLinker { std::vector<std::unique_ptr<const DexFile>> opened_dex_files_; mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - // JNI weak globals to allow dex caches to get unloaded. We lazily delete weak globals when we - // register new dex files. - std::list<jweak> dex_caches_ GUARDED_BY(dex_lock_); + // 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::list<DexCacheData> dex_caches_ GUARDED_BY(dex_lock_); // This contains the class loaders which have class tables. It is populated by // InsertClassTableForClassLoader. @@ -881,8 +998,8 @@ class ClassLinker { // 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_); - // Do we need to search dex caches to find image classes? - bool dex_cache_image_class_lookup_required_; + // Do we need to search dex caches to find boot image classes? + bool dex_cache_boot_image_class_lookup_required_; // 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_; |