Merge "Be more flexible on the code unit size when inlining."
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index d2a90ec..18f215d 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -52,7 +52,7 @@
   static const bool kDefaultGenerateDebugInfo = kIsDebugBuild;
   static const bool kDefaultIncludePatchInformation = false;
   static const size_t kDefaultInlineDepthLimit = 3;
-  static const size_t kDefaultInlineMaxCodeUnits = 18;
+  static const size_t kDefaultInlineMaxCodeUnits = 20;
 
   // Default inlining settings when the space filter is used.
   static constexpr size_t kSpaceFilterInlineDepthLimit = 3;
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 78470db..50cbf5c 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -133,6 +133,7 @@
           && !inst->IsSuspendCheck()
           // If we added an explicit barrier then we should keep it.
           && !inst->IsMemoryBarrier()
+          && !inst->IsParameterValue()
           && !inst->HasUses()) {
         block->RemoveInstruction(inst);
         MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
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);
 
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 9062e1a..bce5915 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -42,6 +42,7 @@
         caller_compilation_unit_(caller_compilation_unit),
         compiler_driver_(compiler_driver),
         depth_(depth),
+        number_of_inlined_instructions_(0),
         handles_(handles) {}
 
   void Run() OVERRIDE;
@@ -49,15 +50,16 @@
   static constexpr const char* kInlinerPassName = "inliner";
 
  private:
-  bool TryInline(HInvoke* invoke_instruction) const;
+  bool TryInline(HInvoke* invoke_instruction);
   bool TryBuildAndInline(ArtMethod* resolved_method,
                          HInvoke* invoke_instruction,
-                         bool same_dex_file) const;
+                         bool same_dex_file);
 
   const DexCompilationUnit& outer_compilation_unit_;
   const DexCompilationUnit& caller_compilation_unit_;
   CompilerDriver* const compiler_driver_;
   const size_t depth_;
+  size_t number_of_inlined_instructions_;
   StackHandleScopeCollection* const handles_;
 
   DISALLOW_COPY_AND_ASSIGN(HInliner);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 851dd4f..f2db330 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3775,11 +3775,15 @@
 class HParameterValue : public HExpression<0> {
  public:
   HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false)
-      : HExpression(parameter_type, SideEffects::None()), index_(index), is_this_(is_this) {}
+      : HExpression(parameter_type, SideEffects::None()),
+        index_(index),
+        is_this_(is_this),
+        can_be_null_(!is_this) {}
 
   uint8_t GetIndex() const { return index_; }
 
-  bool CanBeNull() const OVERRIDE { return !is_this_; }
+  bool CanBeNull() const OVERRIDE { return can_be_null_; }
+  void SetCanBeNull(bool can_be_null) { can_be_null_ = can_be_null; }
 
   bool IsThis() const { return is_this_; }
 
@@ -3793,6 +3797,8 @@
   // Whether or not the parameter value corresponds to 'this' argument.
   const bool is_this_;
 
+  bool can_be_null_;
+
   DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
@@ -4444,6 +4450,7 @@
   // TODO: Can we deopt or debug when we resolve a string?
   bool NeedsEnvironment() const OVERRIDE { return false; }
   bool NeedsDexCache() const OVERRIDE { return true; }
+  bool CanBeNull() const OVERRIDE { return false; }
 
   static SideEffects SideEffectsForArchRuntimeCalls() {
     return SideEffects::CanTriggerGC();
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 5d02948..45b3df0 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -414,7 +414,9 @@
 }
 
 void RTPVisitor::VisitParameterValue(HParameterValue* instr) {
-  if (instr->GetType() == Primitive::kPrimNot) {
+  ScopedObjectAccess soa(Thread::Current());
+  // We check if the existing type is valid: the inliner may have set it.
+  if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
     // TODO: parse the signature and add precise types for the parameters.
     SetClassAsTypeInfo(instr, nullptr, /* is_exact */ false);
   }
diff --git a/runtime/art_method.h b/runtime/art_method.h
index cec1837..6cdc4a6 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -135,14 +135,6 @@
     return (GetAccessFlags() & kAccNative) != 0;
   }
 
-  bool ShouldNotInline() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags() & kAccDontInline) != 0;
-  }
-
-  void SetShouldNotInline() SHARED_REQUIRES(Locks::mutator_lock_) {
-    SetAccessFlags(GetAccessFlags() | kAccDontInline);
-  }
-
   bool IsFastNative() SHARED_REQUIRES(Locks::mutator_lock_) {
     uint32_t mask = kAccFastNative | kAccNative;
     return (GetAccessFlags() & mask) == mask;
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 8b363a6..0d9ec29 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -48,10 +48,6 @@
 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.
 
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
index c108a90..96302fb 100644
--- a/test/441-checker-inliner/src/Main.java
+++ b/test/441-checker-inliner/src/Main.java
@@ -99,10 +99,8 @@
   /// CHECK-DAG:                     Return [<<Result>>]
 
   /// CHECK-START: int Main.InlineAdd() inliner (after)
-  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
-  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
-  /// CHECK-DAG:     <<Add:i\d+>>    Add [<<Const3>>,<<Const5>>]
-  /// CHECK-DAG:                     Return [<<Add>>]
+  /// CHECK-DAG:     <<Const8:i\d+>> IntConstant 8
+  /// CHECK-DAG:                     Return [<<Const8>>]
 
   public static int InlineAdd() {
     return returnAdd(3, 5);
@@ -136,12 +134,9 @@
   /// CHECK-DAG:                     Return [<<Phi>>]
 
   /// CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
-  /// CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
-  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
-  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
-  /// CHECK-DAG:     <<Add:i\d+>>    Add [<<Const1>>,<<Const3>>]
-  /// CHECK-DAG:     <<Sub:i\d+>>    Sub [<<Const5>>,<<Const3>>]
-  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:     <<Const4:i\d+>> IntConstant 4
+  /// CHECK-DAG:     <<Const2:i\d+>> IntConstant 2
+  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Const4>>,<<Const2>>]
   /// CHECK-DAG:                     Return [<<Phi>>]
 
   public static int InlineWithControlFlow(boolean cond) {