Be more flexible on the code unit size when inlining.

This change increases the maximum code unit size, and fold
parameters in the inlinee in the hope to reduce the overall
size of the graph. We then make sure we don't inline methods
that have more than N HInstructions.

Also, remove the kAccDontInline flag on ArtMethod. The compiler
does not need it anymore.

Change-Id: I4cd3da40e551f30ba83b8b274728b87e67f6812e
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 202f3f0..ff90f32 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -40,6 +40,8 @@
 
 namespace art {
 
+static constexpr size_t kMaximumNumberOfHInstructions = 12;
+
 void HInliner::Run() {
   if (graph_->IsDebuggable()) {
     // For simplicity, we currently never inline when the graph is debuggable. This avoids
@@ -169,7 +171,7 @@
   }
 }
 
-bool HInliner::TryInline(HInvoke* invoke_instruction) const {
+bool HInliner::TryInline(HInvoke* invoke_instruction) {
   uint32_t method_index = invoke_instruction->GetDexMethodIndex();
   ScopedObjectAccess soa(Thread::Current());
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
@@ -244,12 +246,6 @@
     return false;
   }
 
-  if (resolved_method->ShouldNotInline()) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
-                   << " was already flagged as non inlineable";
-    return false;
-  }
-
   if (invoke_instruction->IsInvokeStaticOrDirect() &&
       invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) {
     // Case of a static method that cannot be inlined because it implicitly
@@ -271,7 +267,7 @@
 
 bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
                                  HInvoke* invoke_instruction,
-                                 bool same_dex_file) const {
+                                 bool same_dex_file) {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
   const DexFile& callee_dex_file = *resolved_method->GetDexFile();
@@ -335,9 +331,6 @@
   if (!builder.BuildGraph(*code_item)) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be built, so cannot be inlined";
-    // There could be multiple reasons why the graph could not be built, including
-    // unaccessible methods/fields due to using a different dex cache. We do not mark
-    // the method as non-inlineable so that other callers can still try to inline it.
     return false;
   }
 
@@ -345,17 +338,41 @@
                                                   compiler_driver_->GetInstructionSet())) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " cannot be inlined because of the register allocator";
-    resolved_method->SetShouldNotInline();
     return false;
   }
 
   if (!callee_graph->TryBuildingSsa()) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be transformed to SSA";
-    resolved_method->SetShouldNotInline();
     return false;
   }
 
+  size_t parameter_index = 0;
+  for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions());
+       !instructions.Done();
+       instructions.Advance()) {
+    HInstruction* current = instructions.Current();
+    if (current->IsParameterValue()) {
+      HInstruction* argument = invoke_instruction->InputAt(parameter_index++);
+      if (argument->IsNullConstant()) {
+        current->ReplaceWith(callee_graph->GetNullConstant());
+      } else if (argument->IsIntConstant()) {
+        current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue()));
+      } else if (argument->IsLongConstant()) {
+        current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue()));
+      } else if (argument->IsFloatConstant()) {
+        current->ReplaceWith(
+            callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue()));
+      } else if (argument->IsDoubleConstant()) {
+        current->ReplaceWith(
+            callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue()));
+      } else if (argument->GetType() == Primitive::kPrimNot) {
+        current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo());
+        current->AsParameterValue()->SetCanBeNull(argument->CanBeNull());
+      }
+    }
+  }
+
   // Run simple optimizations on the graph.
   HDeadCodeElimination dce(callee_graph, stats_);
   HConstantFolding fold(callee_graph);
@@ -365,10 +382,10 @@
 
   HOptimization* optimizations[] = {
     &intrinsics,
-    &dce,
-    &fold,
     &type_propagation,
     &simplify,
+    &dce,
+    &fold,
   };
 
   for (size_t i = 0; i < arraysize(optimizations); ++i) {
@@ -376,6 +393,7 @@
     optimization->Run();
   }
 
+  size_t number_of_instructions_budget = kMaximumNumberOfHInstructions;
   if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) {
     HInliner inliner(callee_graph,
                      outer_compilation_unit_,
@@ -385,6 +403,7 @@
                      stats_,
                      depth_ + 1);
     inliner.Run();
+    number_of_instructions_budget += inliner.number_of_inlined_instructions_;
   }
 
   // TODO: We should abort only if all predecessors throw. However,
@@ -394,7 +413,6 @@
   if (exit_block == nullptr) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be inlined because it has an infinite loop";
-    resolved_method->SetShouldNotInline();
     return false;
   }
 
@@ -408,24 +426,28 @@
   if (has_throw_predecessor) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be inlined because one branch always throws";
-    resolved_method->SetShouldNotInline();
     return false;
   }
 
   HReversePostOrderIterator it(*callee_graph);
   it.Advance();  // Past the entry block, it does not contain instructions that prevent inlining.
+  size_t number_of_instructions = 0;
   for (; !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     if (block->IsLoopHeader()) {
       VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                      << " could not be inlined because it contains a loop";
-      resolved_method->SetShouldNotInline();
       return false;
     }
 
     for (HInstructionIterator instr_it(block->GetInstructions());
          !instr_it.Done();
          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.";
+        return false;
+      }
       HInstruction* current = instr_it.Current();
 
       if (current->IsInvokeInterface()) {
@@ -433,7 +455,6 @@
         // resolution conflict is currently too high.
         VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                        << " could not be inlined because it has an interface call.";
-        resolved_method->SetShouldNotInline();
         return false;
       }
 
@@ -448,12 +469,11 @@
         VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                        << " could not be inlined because " << current->DebugName()
                        << " it is in a different dex file and requires access to the dex cache";
-        // Do not flag the method as not-inlineable. A caller within the same
-        // dex file could still successfully inline it.
         return false;
       }
     }
   }
+  number_of_inlined_instructions_ += number_of_instructions;
 
   HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);