summaryrefslogtreecommitdiff
path: root/runtime/class_linker.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.h')
-rw-r--r--runtime/class_linker.h193
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_;