AOT compile framework code as non-debuggable
When a debugger attaches, we patch method entry points in framework
code to interpreter bridge. The code will later be jitted as debuggable.
Change-Id: Id148069ccad95e2339ba214742ae3ef4f084f495
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index f7efdc5..5756891 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -695,11 +695,6 @@
Usage("Can't have both --image and (--app-image-fd or --app-image-file)");
}
- if (IsBootImage()) {
- // We need the boot image to always be debuggable.
- compiler_options_->debuggable_ = true;
- }
-
if (oat_filenames_.empty() && oat_fd_ == -1) {
Usage("Output must be supplied with either --oat-file or --oat-fd");
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 936c988..7397709 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2608,18 +2608,6 @@
return nullptr;
}
-const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file,
- uint16_t class_def_idx,
- uint32_t method_idx) {
- bool found;
- OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
- if (!found) {
- return nullptr;
- }
- uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
- return oat_class.GetOatMethod(oat_method_idx).GetQuickCode();
-}
-
bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) {
if (UNLIKELY(method->IsNative() || method->IsProxyMethod())) {
return false;
@@ -2650,6 +2638,11 @@
return true;
}
+ if (Dbg::IsDebuggerActive()) {
+ // Boot image classes are AOT-compiled as non-debuggable.
+ return runtime->GetHeap()->IsInBootImageOatFile(quick_code);
+ }
+
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a9448f7..aa55dac 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -472,12 +472,6 @@
const void* GetQuickOatCodeFor(ArtMethod* method)
SHARED_REQUIRES(Locks::mutator_lock_);
- // Get the oat code for a method from a method index.
- const void* GetQuickOatCodeFor(const DexFile& dex_file,
- uint16_t class_def_idx,
- uint32_t method_idx)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
// Get compiled code for a method, return null if no code
// exists. This is unlike Get..OatCodeFor which will return a bridge
// or interpreter entrypoint.
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 904490a..bc65893 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -28,6 +28,7 @@
#include "class_linker-inl.h"
#include "dex_file-inl.h"
#include "dex_instruction.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocation_record.h"
#include "gc/scoped_gc_critical_section.h"
@@ -570,6 +571,29 @@
return !Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly();
}
+// Used to patch boot image method entry point to interpreter bridge.
+class UpdateEntryPointsClassVisitor : public ClassVisitor {
+ public:
+ explicit UpdateEntryPointsClassVisitor(instrumentation::Instrumentation* instrumentation)
+ : instrumentation_(instrumentation) {}
+
+ bool operator()(mirror::Class* klass) OVERRIDE REQUIRES(Locks::mutator_lock_) {
+ auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+ for (auto& m : klass->GetMethods(pointer_size)) {
+ const void* code = m.GetEntryPointFromQuickCompiledCode();
+ if (Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) &&
+ !m.IsNative() &&
+ !m.IsProxyMethod()) {
+ instrumentation_->UpdateMethodsCode(&m, GetQuickToInterpreterBridge());
+ }
+ }
+ return true;
+ }
+
+ private:
+ instrumentation::Instrumentation* const instrumentation_;
+};
+
void Dbg::GoActive() {
// Enable all debugging features, including scans for breakpoints.
// This is a no-op if we're already active.
@@ -598,6 +622,14 @@
}
Runtime* runtime = Runtime::Current();
+ // Since boot image code is AOT compiled as not debuggable, we need to patch
+ // entry points of methods in boot image to interpreter bridge.
+ if (!runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+ ScopedObjectAccess soa(self);
+ UpdateEntryPointsClassVisitor visitor(runtime->GetInstrumentation());
+ runtime->GetClassLinker()->VisitClasses(&visitor);
+ }
+
ScopedSuspendAll ssa(__FUNCTION__);
if (RequiresDeoptimization()) {
runtime->GetInstrumentation()->EnableDeoptimization();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index a656fb8..4bee462 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -4058,6 +4058,15 @@
return false;
}
+bool Heap::IsInBootImageOatFile(const void* p) const {
+ for (gc::space::ImageSpace* space : boot_image_spaces_) {
+ if (space->GetOatFile()->Contains(p)) {
+ return true;
+ }
+ }
+ return false;
+}
+
void Heap::GetBootImagesSize(uint32_t* boot_image_begin,
uint32_t* boot_image_end,
uint32_t* boot_oat_begin,
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index a181e23..6edb548 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -605,6 +605,9 @@
bool ObjectIsInBootImageSpace(mirror::Object* obj) const
SHARED_REQUIRES(Locks::mutator_lock_);
+ bool IsInBootImageOatFile(const void* p) const
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
void GetBootImagesSize(uint32_t* boot_image_begin,
uint32_t* boot_image_end,
uint32_t* boot_oat_begin,
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 7484635..b107b72 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -104,6 +104,14 @@
method->SetEntryPointFromQuickCompiledCode(quick_code);
}
+bool Instrumentation::NeedDebugVersionForBootImageCode(ArtMethod* method, const void* code) const
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ return Dbg::IsDebuggerActive() &&
+ Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) &&
+ !method->IsNative() &&
+ !method->IsProxyMethod();
+}
+
void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
if (!method->IsInvokable() || method->IsProxyMethod()) {
// Do not change stubs for these methods.
@@ -124,6 +132,9 @@
new_quick_code = GetQuickToInterpreterBridge();
} else if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
new_quick_code = class_linker->GetQuickOatCodeFor(method);
+ if (NeedDebugVersionForBootImageCode(method, new_quick_code)) {
+ new_quick_code = GetQuickToInterpreterBridge();
+ }
} else {
new_quick_code = GetQuickResolutionStub();
}
@@ -136,10 +147,13 @@
// class, all its static methods code will be set to the instrumentation entry point.
// For more details, see ClassLinker::FixupStaticTrampolines.
if (is_class_initialized || !method->IsStatic() || method->IsConstructor()) {
- if (entry_exit_stubs_installed_) {
+ new_quick_code = class_linker->GetQuickOatCodeFor(method);
+ if (NeedDebugVersionForBootImageCode(method, new_quick_code)) {
+ // Oat code should not be used. Don't install instrumentation stub and
+ // use interpreter for instrumentation.
+ new_quick_code = GetQuickToInterpreterBridge();
+ } else if (entry_exit_stubs_installed_) {
new_quick_code = GetQuickInstrumentationEntryPoint();
- } else {
- new_quick_code = class_linker->GetQuickOatCodeFor(method);
}
} else {
new_quick_code = GetQuickResolutionStub();
@@ -775,6 +789,9 @@
UpdateEntrypoints(method, GetQuickResolutionStub());
} else {
const void* quick_code = class_linker->GetQuickOatCodeFor(method);
+ if (NeedDebugVersionForBootImageCode(method, quick_code)) {
+ quick_code = GetQuickToInterpreterBridge();
+ }
UpdateEntrypoints(method, quick_code);
}
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index e3cbf53..2e4be6b 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -247,6 +247,11 @@
return forced_interpret_only_;
}
+ // Code is in boot image oat file which isn't compiled as debuggable.
+ // Need debug version (interpreter or jitted) if that's the case.
+ bool NeedDebugVersionForBootImageCode(ArtMethod* method, const void* code) const
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
bool AreExitStubsInstalled() const {
return instrumentation_stubs_installed_;
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 910163c..fb91a8c 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -228,6 +228,10 @@
return End() - Begin();
}
+ bool Contains(const void* p) const {
+ return p >= Begin() && p < End();
+ }
+
size_t BssSize() const {
return BssEnd() - BssBegin();
}