diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/class_linker.cc | 30 | ||||
-rw-r--r-- | runtime/class_linker.h | 4 | ||||
-rw-r--r-- | runtime/class_linker_test.cc | 20 | ||||
-rw-r--r-- | runtime/debugger.cc | 12 | ||||
-rw-r--r-- | runtime/mirror/class.h | 5 |
5 files changed, 69 insertions, 2 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f092772..7a8e4a3 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -5926,4 +5926,34 @@ std::size_t ClassLinker::ClassDescriptorHashEquals::operator()(const char* descr return ComputeModifiedUtf8Hash(descriptor); } +bool ClassLinker::MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m) { + // Non-image methods don't use direct code pointer. + if (!m->GetDeclaringClass()->IsBootStrapClassLoaded()) { + return false; + } + if (m->IsPrivate()) { + // The method can only be called inside its own oat file. Therefore it won't be called using + // its direct code if the oat file has been compiled in PIC mode. + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + const DexFile& dex_file = m->GetDeclaringClass()->GetDexFile(); + const OatFile::OatDexFile* oat_dex_file = class_linker->FindOpenedOatDexFileForDexFile(dex_file); + if (oat_dex_file == nullptr) { + // No oat file: the method has not been compiled. + return false; + } + const OatFile* oat_file = oat_dex_file->GetOatFile(); + return oat_file != nullptr && !oat_file->IsPic(); + } else { + // The method can be called outside its own oat file. Therefore it won't be called using its + // direct code pointer only if all loaded oat files have been compiled in PIC mode. + ReaderMutexLock mu(Thread::Current(), dex_lock_); + for (const OatFile* oat_file : oat_files_) { + if (!oat_file->IsPic()) { + return true; + } + } + return false; + } +} + } // namespace art diff --git a/runtime/class_linker.h b/runtime/class_linker.h index b78d0b5..55332f8 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -471,6 +471,10 @@ class ClassLinker { LOCKS_EXCLUDED(Locks::classlinker_classes_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns true if the method can be called with its direct code pointer, false otherwise. + bool MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + private: const OatFile::OatMethod FindOatMethodFor(mirror::ArtMethod* method, bool* found) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 99d0746..c22c51e 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1141,4 +1141,24 @@ TEST_F(ClassLinkerTest, Preverified_App) { CheckPreverified(statics.Get(), true); } +TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) { + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<3> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")))); + + // java.lang.Object is a bootstrap class. + Handle<mirror::Class> jlo_class( + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); + ASSERT_TRUE(jlo_class.Get() != nullptr); + EXPECT_TRUE(jlo_class.Get()->IsBootStrapClassLoaded()); + + // Statics is not a bootstrap class. + Handle<mirror::Class> statics( + hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader))); + ASSERT_TRUE(statics.Get() != nullptr); + EXPECT_FALSE(statics.Get()->IsBootStrapClassLoaded()); +} + } // namespace art diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 49b132d..86d027b 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -3266,8 +3266,16 @@ static DeoptimizationRequest::Kind GetRequiredDeoptimizationKind(Thread* self, ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); const bool is_compiled = class_linker->GetOatMethodQuickCodeFor(m) != nullptr; if (is_compiled) { - VLOG(jdwp) << "Need selective deoptimization for compiled method " << PrettyMethod(m); - return DeoptimizationRequest::kSelectiveDeoptimization; + // If the method may be called through its direct code pointer (without loading + // its updated entrypoint), we need full deoptimization to not miss the breakpoint. + if (class_linker->MayBeCalledWithDirectCodePointer(m)) { + VLOG(jdwp) << "Need full deoptimization because of possible direct code call " + << "into image for compiled method " << PrettyMethod(m); + return DeoptimizationRequest::kFullDeoptimization; + } else { + VLOG(jdwp) << "Need selective deoptimization for compiled method " << PrettyMethod(m); + return DeoptimizationRequest::kSelectiveDeoptimization; + } } else { // Method is not compiled: we don't need to deoptimize. VLOG(jdwp) << "No need for deoptimization for non-compiled method " << PrettyMethod(m); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index a77972e..2fc5ffb 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1043,6 +1043,11 @@ class MANAGED Class FINAL : public Object { DISALLOW_COPY_AND_ASSIGN(InitializeClassVisitor); }; + // Returns true if the class loader is null, ie the class loader is the boot strap class loader. + bool IsBootStrapClassLoaded() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetClassLoader() == nullptr; + } + private: void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |