Revert "Revert "Tweak inlining heuristics.""

This reverts commit b17d1ccff0ac26fc22df671907ba2b4f4c656ce4.

Change-Id: I26f6f8702a448c3da12662cbc6bc0f6e562bc40b
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9ad1bee..f8032bb 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -53,7 +53,7 @@
   static const bool kDefaultGenerateDebugInfo = kIsDebugBuild;
   static const bool kDefaultIncludePatchInformation = false;
   static const size_t kDefaultInlineDepthLimit = 3;
-  static const size_t kDefaultInlineMaxCodeUnits = 20;
+  static const size_t kDefaultInlineMaxCodeUnits = 32;
   static constexpr size_t kUnsetInlineDepthLimit = -1;
   static constexpr size_t kUnsetInlineMaxCodeUnits = -1;
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 0e50416..7c2b8bc 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -42,7 +42,14 @@
 
 namespace art {
 
-static constexpr size_t kMaximumNumberOfHInstructions = 12;
+static constexpr size_t kMaximumNumberOfHInstructions = 32;
+
+// Limit the number of dex registers that we accumulate while inlining
+// to avoid creating large amount of nested environments.
+static constexpr size_t kMaximumNumberOfCumulatedDexRegisters = 64;
+
+// Avoid inlining within a huge method due to memory pressure.
+static constexpr size_t kMaximumCodeUnitSize = 4096;
 
 void HInliner::Run() {
   const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
@@ -50,6 +57,9 @@
       || (compiler_options.GetInlineMaxCodeUnits() == 0)) {
     return;
   }
+  if (caller_compilation_unit_.GetCodeItem()->insns_size_in_code_units_ > kMaximumCodeUnitSize) {
+    return;
+  }
   if (graph_->IsDebuggable()) {
     // For simplicity, we currently never inline when the graph is debuggable. This avoids
     // doing some logic in the runtime to discover if a method could have been inlined.
@@ -589,6 +599,7 @@
                      compiler_driver_,
                      handles_,
                      stats_,
+                     total_number_of_dex_registers_ + code_item->registers_size_,
                      depth_ + 1);
     inliner.Run();
     number_of_instructions_budget += inliner.number_of_inlined_instructions_;
@@ -620,6 +631,10 @@
   HReversePostOrderIterator it(*callee_graph);
   it.Advance();  // Past the entry block, it does not contain instructions that prevent inlining.
   size_t number_of_instructions = 0;
+
+  bool can_inline_environment =
+      total_number_of_dex_registers_ < kMaximumNumberOfCumulatedDexRegisters;
+
   for (; !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     if (block->IsLoopHeader()) {
@@ -633,10 +648,17 @@
          instr_it.Advance()) {
       if (number_of_instructions++ ==  number_of_instructions_budget) {
         VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
-                       << " could not be inlined because it is too big.";
+                       << " is not inlined because its caller has reached"
+                       << " its instruction budget limit.";
         return false;
       }
       HInstruction* current = instr_it.Current();
+      if (!can_inline_environment && current->NeedsEnvironment()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                       << " is not inlined because its caller has reached"
+                       << " its environment budget limit.";
+        return false;
+      }
 
       if (current->IsInvokeInterface()) {
         // Disable inlining of interface calls. The cost in case of entering the
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 7b9fb73..8de510e 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -40,13 +40,15 @@
            CompilerDriver* compiler_driver,
            StackHandleScopeCollection* handles,
            OptimizingCompilerStats* stats,
-           size_t depth = 0)
+           size_t total_number_of_dex_registers,
+           size_t depth)
       : HOptimization(outer_graph, kInlinerPassName, stats),
         outermost_graph_(outermost_graph),
         outer_compilation_unit_(outer_compilation_unit),
         caller_compilation_unit_(caller_compilation_unit),
         codegen_(codegen),
         compiler_driver_(compiler_driver),
+        total_number_of_dex_registers_(total_number_of_dex_registers),
         depth_(depth),
         number_of_inlined_instructions_(0),
         handles_(handles) {}
@@ -88,6 +90,7 @@
   const DexCompilationUnit& caller_compilation_unit_;
   CodeGenerator* const codegen_;
   CompilerDriver* const compiler_driver_;
+  const size_t total_number_of_dex_registers_;
   const size_t depth_;
   size_t number_of_inlined_instructions_;
   StackHandleScopeCollection* const handles_;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 3de870e..3f9e151 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -426,8 +426,18 @@
   if (!should_inline) {
     return;
   }
+  size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_;
   HInliner* inliner = new (graph->GetArena()) HInliner(
-      graph, graph, codegen, dex_compilation_unit, dex_compilation_unit, driver, handles, stats);
+      graph,
+      graph,
+      codegen,
+      dex_compilation_unit,
+      dex_compilation_unit,
+      driver,
+      handles,
+      stats,
+      number_of_dex_registers,
+      /* depth */ 0);
   HOptimization* optimizations[] = { inliner };
 
   RunOptimizations(optimizations, arraysize(optimizations), pass_observer);
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 6e7ba40..3e6d1f4 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -127,7 +127,7 @@
   }
 
 
-  /// CHECK-START: void Main.constantIndexing2(int[]) BCE (before)
+  /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (before)
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
   /// CHECK: BoundsCheck
@@ -137,7 +137,7 @@
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
 
-  /// CHECK-START: void Main.constantIndexing2(int[]) BCE (after)
+  /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (after)
   /// CHECK: LessThanOrEqual
   /// CHECK: Deoptimize
   /// CHECK-NOT: BoundsCheck
@@ -151,12 +151,15 @@
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
 
-  static void constantIndexing2(int[] array) {
+  static void $opt$noinline$constantIndexing2(int[] array) {
     array[1] = 1;
     array[2] = 1;
     array[3] = 1;
     array[4] = 1;
     array[-1] = 1;
+    if (array[1] == 1) {
+      throw new Error("");
+    }
   }
 
 
@@ -655,10 +658,10 @@
     try {
       assertIsManaged();
       // This will cause AIOOBE.
-      constantIndexing2(new int[3]);
+      $opt$noinline$constantIndexing2(new int[3]);
     } catch (ArrayIndexOutOfBoundsException e) {
       assertIsManaged();  // This is to ensure that single-frame deoptimization works.
-                          // Will need to be updated if constantIndexing2 is inlined.
+                          // Will need to be updated if $opt$noinline$constantIndexing2 is inlined.
       try {
         // This will cause AIOOBE.
         constantIndexingForward6(new int[3]);
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 375a3fc..4f89e91 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -40,15 +40,17 @@
       uint32_t value = 0;
       CHECK(GetVReg(m, 0, kIntVReg, &value));
       CHECK_EQ(value, 42u);
-    } else if (m_name.compare("testIntervalHole") == 0) {
+    } else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) {
+      uint32_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
+      uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2;
       found_method_ = true;
       uint32_t value = 0;
       if (GetCurrentQuickFrame() != nullptr &&
           GetCurrentOatQuickMethodHeader()->IsOptimized() &&
           !Runtime::Current()->IsDebuggable()) {
-        CHECK_EQ(GetVReg(m, 0, kIntVReg, &value), false);
+        CHECK_EQ(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value), false);
       } else {
-        CHECK(GetVReg(m, 0, kIntVReg, &value));
+        CHECK(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value));
         CHECK_EQ(value, 1u);
       }
     }
diff --git a/test/466-get-live-vreg/src/Main.java b/test/466-get-live-vreg/src/Main.java
index d036a24..19032601 100644
--- a/test/466-get-live-vreg/src/Main.java
+++ b/test/466-get-live-vreg/src/Main.java
@@ -31,7 +31,7 @@
     }
   }
 
-  static void testIntervalHole(int arg, boolean test) {
+  static void $opt$noinline$testIntervalHole(int arg, boolean test) {
     // Move the argument to callee save to ensure it is in
     // a readable register.
     moveArgToCalleeSave();
@@ -44,6 +44,9 @@
       // The environment use of `arg` should not make it live.
       doStaticNativeCallLiveVreg();
     }
+    if (staticField1 == 2) {
+      throw new Error("");
+    }
   }
 
   static native void doStaticNativeCallLiveVreg();
@@ -67,7 +70,7 @@
   static void testWrapperIntervalHole(int arg, boolean test) {
     try {
       Thread.sleep(0);
-      testIntervalHole(arg, test);
+      $opt$noinline$testIntervalHole(arg, test);
     } catch (Exception e) {
       throw new Error(e);
     }
diff --git a/test/476-checker-ctor-memory-barrier/src/Main.java b/test/476-checker-ctor-memory-barrier/src/Main.java
index 41bec05..c2a2a10 100644
--- a/test/476-checker-ctor-memory-barrier/src/Main.java
+++ b/test/476-checker-ctor-memory-barrier/src/Main.java
@@ -25,13 +25,14 @@
 class ClassWithFinals {
   public final int x;
   public ClassWithFinals obj;
+  public static boolean doThrow = false;
 
   /// CHECK-START: void ClassWithFinals.<init>(boolean) register (after)
   /// CHECK:      MemoryBarrier kind:StoreStore
   /// CHECK-NEXT: ReturnVoid
   public ClassWithFinals(boolean cond) {
     x = 0;
-    if (cond) {
+    if (doThrow) {
       // avoid inlining
       throw new RuntimeException();
     }