ART: Ignore unneeded environment uses.

Some of the environment uses of primitive-typed values are
not really needed in non-debuggable/non-OSR methods. Ignoring
those uses during liveness analysis significantly reduces the
size of stack maps in the oat file.

Code reduction on arm64:
boot-framework.oat: -1.8%
boot.oat:           -1.4%

Test: 466-get-live-vreg, 564-checker-condition-liveness.
Test: 639-checker-code-sinking.
Test: angler boots to GUI.
Test: test-art-host, test-art-target

Change-Id: I91dcb6d0a8ab86f56c7b243bf9b100f69bcd5979
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index f6bd052..2f782f3 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -195,14 +195,19 @@
         // SsaLivenessAnalysis.
         for (size_t i = 0, e = environment->Size(); i < e; ++i) {
           HInstruction* instruction = environment->GetInstructionAt(i);
+          if (instruction == nullptr) {
+            continue;
+          }
           bool should_be_live = ShouldBeLiveForEnvironment(current, instruction);
+          // If this environment use does not keep the instruction live, it does not
+          // affect the live range of that instruction.
           if (should_be_live) {
             CHECK(instruction->HasSsaIndex()) << instruction->DebugName();
             live_in->SetBit(instruction->GetSsaIndex());
-          }
-          if (instruction != nullptr) {
-            instruction->GetLiveInterval()->AddUse(
-                current, environment, i, /* actual_user */ nullptr, should_be_live);
+            instruction->GetLiveInterval()->AddUse(current,
+                                                   environment,
+                                                   i,
+                                                   /* actual_user */ nullptr);
           }
         }
       }
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index f83bb52..83ca5bd 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -300,8 +300,7 @@
   void AddUse(HInstruction* instruction,
               HEnvironment* environment,
               size_t input_index,
-              HInstruction* actual_user = nullptr,
-              bool keep_alive = false) {
+              HInstruction* actual_user = nullptr) {
     bool is_environment = (environment != nullptr);
     LocationSummary* locations = instruction->GetLocations();
     if (actual_user == nullptr) {
@@ -359,12 +358,6 @@
       uses_.push_front(*new_use);
     }
 
-    if (is_environment && !keep_alive) {
-      // If this environment use does not keep the instruction live, it does not
-      // affect the live range of that instruction.
-      return;
-    }
-
     size_t start_block_position = instruction->GetBlock()->GetLifetimeStart();
     if (first_range_ == nullptr) {
       // First time we see a use of that interval.
@@ -1157,8 +1150,11 @@
  *     of an instruction that has a primitive type make the instruction live.
  *     If the graph does not have the debuggable property, the environment
  *     use has no effect, and may get a 'none' value after register allocation.
+ * (d) When compiling in OSR mode, all loops in the compiled method may be entered
+ *     from the interpreter via SuspendCheck; such use in SuspendCheck makes the instruction
+ *     live.
  *
- * (b) and (c) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
+ * (b), (c) and (d) are implemented through SsaLivenessAnalysis::ShouldBeLiveForEnvironment.
  */
 class SsaLivenessAnalysis : public ValueObject {
  public:
@@ -1259,14 +1255,18 @@
   // Returns whether `instruction` in an HEnvironment held by `env_holder`
   // should be kept live by the HEnvironment.
   static bool ShouldBeLiveForEnvironment(HInstruction* env_holder, HInstruction* instruction) {
-    if (instruction == nullptr) return false;
+    DCHECK(instruction != nullptr);
     // A value that's not live in compiled code may still be needed in interpreter,
     // due to code motion, etc.
     if (env_holder->IsDeoptimize()) return true;
     // A value live at a throwing instruction in a try block may be copied by
     // the exception handler to its location at the top of the catch block.
     if (env_holder->CanThrowIntoCatchBlock()) return true;
-    if (instruction->GetBlock()->GetGraph()->IsDebuggable()) return true;
+    HGraph* graph = instruction->GetBlock()->GetGraph();
+    if (graph->IsDebuggable()) return true;
+    // When compiling in OSR mode, all loops in the compiled method may be entered
+    // from the interpreter via SuspendCheck; thus we need to preserve the environment.
+    if (env_holder->IsSuspendCheck() && graph->IsCompilingOsr()) return true;
     return instruction->GetType() == DataType::Type::kReference;
   }
 
diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc
index b9bfbaa..ae5e4e7 100644
--- a/compiler/optimizing/ssa_liveness_analysis_test.cc
+++ b/compiler/optimizing/ssa_liveness_analysis_test.cc
@@ -134,12 +134,12 @@
   static const char* const expected[] = {
       "ranges: { [2,21) }, uses: { 15 17 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [4,21) }, uses: { 19 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [4,21) }, uses: { 19 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [6,21) }, uses: { 21 }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [6,21) }, uses: { 21 }, { } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
       // Environment uses do not keep the non-reference argument alive.
-      "ranges: { [8,10) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [8,10) }, uses: { }, { } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment uses keep the reference argument alive.
       "ranges: { [10,19) }, uses: { }, { 15 19 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };
@@ -207,11 +207,11 @@
   static const char* const expected[] = {
       "ranges: { [2,23) }, uses: { 15 17 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [4,23) }, uses: { 19 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 "
+      "ranges: { [4,23) }, uses: { 19 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 "
           "is_high: 0",
-      "ranges: { [6,23) }, uses: { 23 }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [6,23) }, uses: { 23 }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment use in HDeoptimize keeps even the non-reference argument alive.
-      "ranges: { [8,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
+      "ranges: { [8,21) }, uses: { }, { 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
       // Environment uses keep the reference argument alive.
       "ranges: { [10,21) }, uses: { }, { 15 21 } is_fixed: 0, is_split: 0 is_low: 0 is_high: 0",
   };