summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/class_linker.cc30
-rw-r--r--runtime/class_linker.h4
-rw-r--r--runtime/class_linker_test.cc20
-rw-r--r--runtime/debugger.cc12
-rw-r--r--runtime/mirror/class.h5
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_);