OSDN Git Service

AOT compile framework code as non-debuggable
authorMingyao Yang <mingyao@google.com>
Fri, 29 Jan 2016 20:12:49 +0000 (12:12 -0800)
committerMingyao Yang <mingyao@google.com>
Tue, 23 Feb 2016 21:44:50 +0000 (13:44 -0800)
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

dex2oat/dex2oat.cc
runtime/class_linker.cc
runtime/class_linker.h
runtime/debugger.cc
runtime/gc/heap.cc
runtime/gc/heap.h
runtime/instrumentation.cc
runtime/instrumentation.h
runtime/oat_file.h

index f7efdc5..5756891 100644 (file)
@@ -695,11 +695,6 @@ class Dex2Oat FINAL {
       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");
     }
index 936c988..7397709 100644 (file)
@@ -2608,18 +2608,6 @@ const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) {
   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 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void*
     return true;
   }
 
+  if (Dbg::IsDebuggerActive()) {
+    // Boot image classes are AOT-compiled as non-debuggable.
+    return runtime->GetHeap()->IsInBootImageOatFile(quick_code);
+  }
+
   return false;
 }
 
index a9448f7..aa55dac 100644 (file)
@@ -472,12 +472,6 @@ class ClassLinker {
   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.
index 904490a..bc65893 100644 (file)
@@ -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 @@ bool Dbg::RequiresDeoptimization() {
   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 @@ void Dbg::GoActive() {
   }
 
   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();
index a656fb8..4bee462 100644 (file)
@@ -4058,6 +4058,15 @@ bool Heap::ObjectIsInBootImageSpace(mirror::Object* obj) const {
   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,
index a181e23..6edb548 100644 (file)
@@ -605,6 +605,9 @@ class Heap {
   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,
index 7484635..b107b72 100644 (file)
@@ -104,6 +104,14 @@ static void UpdateEntrypoints(ArtMethod* method, const void* quick_code)
   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 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
       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 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
       // 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 @@ void Instrumentation::Undeoptimize(ArtMethod* method) {
       UpdateEntrypoints(method, GetQuickResolutionStub());
     } else {
       const void* quick_code = class_linker->GetQuickOatCodeFor(method);
+      if (NeedDebugVersionForBootImageCode(method, quick_code)) {
+        quick_code = GetQuickToInterpreterBridge();
+      }
       UpdateEntrypoints(method, quick_code);
     }
 
index e3cbf53..2e4be6b 100644 (file)
@@ -247,6 +247,11 @@ class Instrumentation {
     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_;
   }
index 910163c..fb91a8c 100644 (file)
@@ -228,6 +228,10 @@ class OatFile {
     return End() - Begin();
   }
 
+  bool Contains(const void* p) const {
+    return p >= Begin() && p < End();
+  }
+
   size_t BssSize() const {
     return BssEnd() - BssBegin();
   }