Remember whether a method was worth inlining.

Change-Id: I9d8efe312b264739ac6307f966e43c1d7650a3ca
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index bd9267c..968fe3e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -118,6 +118,29 @@
     return false;
   }
 
+  if (resolved_method->ShouldNotInline()) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
+                   << " was already flagged as non inlineable";
+    return false;
+  }
+
+  if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index)) {
+    resolved_method->SetShouldNotInline();
+    return false;
+  }
+
+  VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
+  MaybeRecordStat(kInlinedInvoke);
+  return true;
+}
+
+bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method,
+                                 HInvoke* invoke_instruction,
+                                 uint32_t method_index) const {
+  ScopedObjectAccess soa(Thread::Current());
+  const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
+  const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
+
   DexCompilationUnit dex_compilation_unit(
     nullptr,
     outer_compilation_unit_.GetClassLoader(),
@@ -225,8 +248,6 @@
   // instruction id of the caller, so that new instructions added
   // after optimizations get a unique id.
   graph_->SetCurrentInstructionId(callee_graph->GetNextInstructionId());
-  VLOG(compiler) << "Successfully inlined " << PrettyMethod(method_index, outer_dex_file);
-  MaybeRecordStat(kInlinedInvoke);
   return true;
 }
 
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 2b08d3d..1251977 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -46,6 +46,9 @@
 
  private:
   bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const;
+  bool TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method,
+                         HInvoke* invoke_instruction,
+                         uint32_t method_index) const;
 
   const DexCompilationUnit& outer_compilation_unit_;
   CompilerDriver* const compiler_driver_;
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index d878f25..aaa9b56 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -125,6 +125,14 @@
     return (GetAccessFlags() & kAccNative) != 0;
   }
 
+  bool ShouldNotInline() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return (GetAccessFlags() & kAccDontInline) != 0;
+  }
+
+  void SetShouldNotInline() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    SetAccessFlags(GetAccessFlags() | kAccDontInline);
+  }
+
   bool IsFastNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t mask = kAccFastNative | kAccNative;
     return (GetAccessFlags() & mask) == mask;
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 09dc78a..e7bd207 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -48,6 +48,10 @@
 static constexpr uint32_t kAccFastNative =           0x00080000;  // method (dex only)
 static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
 
+// Flag is set if the compiler decides it is not worth trying
+// to inline the method. This avoids other callers to try it again and again.
+static constexpr uint32_t kAccDontInline =           0x00400000;  // method (dex only)
+
 // Special runtime-only flags.
 // Note: if only kAccClassIsReference is set, we have a soft reference.