Merge "Replace StackHandleScopeCollection with VariableSizedHandleScope"
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 7e58d78..bfb342f 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -322,7 +322,7 @@
     ThreadOffset<kPointerSize> jni_start =
         is_synchronized
             ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStartSynchronized)
-            : (is_fast_native
+            : ((is_fast_native && !reference_return)  // TODO: support @FastNative returning obj
                    ? QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodFastStart)
                    : QUICK_ENTRYPOINT_OFFSET(kPointerSize, pJniMethodStart));
 
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index c501ccf..55fcb12 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -87,11 +87,12 @@
     : HOptimization(graph, kInductionPassName),
       global_depth_(0),
       stack_(graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
-      scc_(graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
       map_(std::less<HInstruction*>(),
            graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
+      scc_(graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
       cycle_(std::less<HInstruction*>(),
              graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)),
+      type_(Primitive::kPrimVoid),
       induction_(std::less<HLoopInformation*>(),
                  graph->GetArena()->Adapter(kArenaAllocInductionVarAnalysis)) {
 }
@@ -103,7 +104,6 @@
   for (HReversePostOrderIterator it_graph(*graph_); !it_graph.Done(); it_graph.Advance()) {
     HBasicBlock* graph_block = it_graph.Current();
     // Don't analyze irreducible loops.
-    // TODO(ajcbik): could/should we remove this restriction?
     if (graph_block->IsLoopHeader() && !graph_block->GetLoopInformation()->IsIrreducible()) {
       VisitLoop(graph_block->GetLoopInformation());
     }
@@ -121,7 +121,7 @@
     HBasicBlock* loop_block = it_loop.Current();
     DCHECK(loop_block->IsInLoop());
     if (loop_block->GetLoopInformation() != loop) {
-      continue;  // Inner loops already visited.
+      continue;  // Inner loops visited later.
     }
     // Visit phi-operations and instructions.
     for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
@@ -285,6 +285,9 @@
     } else if (instruction->IsSub()) {
       update = SolveAddSub(
           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
+    } else if (instruction->IsXor()) {
+      update = SolveXor(
+          loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), true);
     } else if (instruction->IsTypeConversion()) {
       update = SolveCnv(instruction->AsTypeConversion());
     }
@@ -553,6 +556,27 @@
   return nullptr;
 }
 
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveXor(HLoopInformation* loop,
+                                                                      HInstruction* entry_phi,
+                                                                      HInstruction* instruction,
+                                                                      HInstruction* x,
+                                                                      HInstruction* y,
+                                                                      bool is_first_call) {
+  InductionInfo* b = LookupInfo(loop, y);
+  // Solve within a tight cycle on x = x ^ c.
+  if (b != nullptr && b->induction_class == kInvariant) {
+    if (x == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
+      InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
+      return CreateInduction(kPeriodic, CreateInvariantOp(kXor, initial, b), initial, type_);
+    }
+  }
+  // Try the other way around if considered for first time.
+  if (is_first_call) {
+    return SolveXor(loop, entry_phi, instruction, y, x, false);
+  }
+  return nullptr;
+}
+
 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveCnv(HTypeConversion* conversion) {
   Primitive::Type from = conversion->GetInputType();
   Primitive::Type to = conversion->GetResultType();
@@ -850,8 +874,8 @@
   int64_t value = -1;
   if (IsExact(a, &value)) {
     if (value == 0) {
-      // Simplify 0 + b = b, 0 * b = 0.
-      if (op == kAdd) {
+      // Simplify 0 + b = b, 0 ^ b = b, 0 * b = 0.
+      if (op == kAdd || op == kXor) {
         return b;
       } else if (op == kMul) {
         return a;
@@ -867,8 +891,8 @@
   }
   if (IsExact(b, &value)) {
     if (value == 0) {
-      // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, -0 = 0.
-      if (op == kAdd || op == kSub) {
+      // Simplify a + 0 = a, a - 0 = a, a ^ 0 = a, a * 0 = 0, -0 = 0.
+      if (op == kAdd || op == kSub || op == kXor) {
         return a;
       } else if (op == kMul || op == kNeg) {
         return b;
@@ -939,6 +963,7 @@
         case kNeg:   inv += " - ";  break;
         case kMul:   inv += " * ";  break;
         case kDiv:   inv += " / ";  break;
+        case kXor:   inv += " ^ ";  break;
         case kLT:    inv += " < ";  break;
         case kLE:    inv += " <= "; break;
         case kGT:    inv += " > ";  break;
diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h
index cd4c830..06aee31 100644
--- a/compiler/optimizing/induction_var_analysis.h
+++ b/compiler/optimizing/induction_var_analysis.h
@@ -64,6 +64,7 @@
     kNeg,
     kMul,
     kDiv,
+    kXor,
     kFetch,
     // Trip-counts.
     kTripCountInLoop,        // valid in full loop; loop is finite
@@ -171,7 +172,13 @@
                              HInstruction* x,
                              HInstruction* y,
                              InductionOp op,
-                             bool is_first_call);
+                             bool is_first_call);  // possibly swaps x and y to try again
+  InductionInfo* SolveXor(HLoopInformation* loop,
+                          HInstruction* entry_phi,
+                          HInstruction* instruction,
+                          HInstruction* x,
+                          HInstruction* y,
+                          bool is_first_call);  // possibly swaps x and y to try again
   InductionInfo* SolveCnv(HTypeConversion* conversion);
 
   // Trip count information.
@@ -219,8 +226,8 @@
   // Temporary book-keeping during the analysis.
   uint32_t global_depth_;
   ArenaVector<HInstruction*> stack_;
-  ArenaVector<HInstruction*> scc_;
   ArenaSafeMap<HInstruction*, NodeInfo> map_;
+  ArenaVector<HInstruction*> scc_;
   ArenaSafeMap<HInstruction*, InductionInfo*> cycle_;
   Primitive::Type type_;
 
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 292bc4e..7c467f6 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -107,7 +107,7 @@
   }
 
   // Builds if-statement at depth d.
-  HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
+  HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
     HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
     HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
     HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
@@ -259,15 +259,15 @@
   //   k = - i;
   // }
   BuildLoopNest(1);
-  HInstruction *add = InsertInstruction(
+  HInstruction* add = InsertInstruction(
       new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
-  HInstruction *mul = InsertInstruction(
+  HInstruction* mul = InsertInstruction(
       new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
-  HInstruction *shl = InsertInstruction(
+  HInstruction* shl = InsertInstruction(
       new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
-  HInstruction *neg = InsertInstruction(
+  HInstruction* neg = InsertInstruction(
       new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
   PerformInductionVarAnalysis();
 
@@ -291,10 +291,10 @@
   HPhi* k = InsertLoopPhi(0, 0);
   k->AddInput(constant0_);
 
-  HInstruction *add = InsertInstruction(
+  HInstruction* add = InsertInstruction(
       new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
   HInstruction* store1 = InsertArrayStore(add, 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
   HInstruction* store2 = InsertArrayStore(sub, 0);
   k->AddInput(sub);
@@ -381,7 +381,7 @@
   k->AddInput(constant0_);
 
   HInstruction* store = InsertArrayStore(k, 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
   k->AddInput(sub);
   PerformInductionVarAnalysis();
@@ -407,7 +407,7 @@
 
   HInstruction* store = InsertArrayStore(k, 0);
   k->AddInput(t);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
   t->AddInput(sub);
   PerformInductionVarAnalysis();
@@ -431,15 +431,15 @@
   HPhi* k = InsertLoopPhi(0, 0);
   k->AddInput(constant0_);
 
-  HInstruction *add = InsertInstruction(
+  HInstruction* add = InsertInstruction(
       new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, k, constant100_), 0);
-  HInstruction *mul = InsertInstruction(
+  HInstruction* mul = InsertInstruction(
       new (&allocator_) HMul(Primitive::kPrimInt, k, constant100_), 0);
-  HInstruction *shl = InsertInstruction(
+  HInstruction* shl = InsertInstruction(
       new (&allocator_) HShl(Primitive::kPrimInt, k, constant1_), 0);
-  HInstruction *neg = InsertInstruction(
+  HInstruction* neg = InsertInstruction(
       new (&allocator_) HNeg(Primitive::kPrimInt, k), 0);
   k->AddInput(
       InsertInstruction(new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0));
@@ -497,7 +497,7 @@
   k->AddInput(constant0_);
 
   HInstruction* store = InsertArrayStore(k, 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k), 0);
   k->AddInput(sub);
   PerformInductionVarAnalysis();
@@ -506,6 +506,45 @@
   EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
 }
 
+TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
+  // Setup:
+  // k = 0;
+  // for (int i = 0; i < 100; i++) {
+  //   a[k] = 0;
+  //   k = k ^ 1;
+  // }
+  BuildLoopNest(1);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+
+  HInstruction* store = InsertArrayStore(k, 0);
+  HInstruction* x = InsertInstruction(
+      new (&allocator_) HXor(Primitive::kPrimInt, k, constant1_), 0);
+  k->AddInput(x);
+  PerformInductionVarAnalysis();
+
+  EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
+  EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
+}
+
+TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
+  // Setup:
+  // k = 100;
+  // for (int i = 0; i < 100; i++) {
+  //   k = k ^ 100;
+  // }
+  BuildLoopNest(1);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant100_);
+
+  HInstruction* x = InsertInstruction(
+      new (&allocator_) HXor(Primitive::kPrimInt, k, constant100_), 0);
+  k->AddInput(x);
+  PerformInductionVarAnalysis();
+
+  EXPECT_STREQ("periodic(((100) ^ (100)), (100)):PrimInt", GetInductionInfo(x, 0).c_str());
+}
+
 TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
   // Setup:
   // k = 0;
@@ -526,15 +565,15 @@
   k_header->AddInput(k_body);
 
   // Derived expressions.
-  HInstruction *add = InsertInstruction(
+  HInstruction* add = InsertInstruction(
       new (&allocator_) HAdd(Primitive::kPrimInt, k_body, constant100_), 0);
-  HInstruction *sub = InsertInstruction(
+  HInstruction* sub = InsertInstruction(
       new (&allocator_) HSub(Primitive::kPrimInt, k_body, constant100_), 0);
-  HInstruction *mul = InsertInstruction(
+  HInstruction* mul = InsertInstruction(
       new (&allocator_) HMul(Primitive::kPrimInt, k_body, constant100_), 0);
-  HInstruction *shl = InsertInstruction(
+  HInstruction* shl = InsertInstruction(
       new (&allocator_) HShl(Primitive::kPrimInt, k_body, constant1_), 0);
-  HInstruction *neg = InsertInstruction(
+  HInstruction* neg = InsertInstruction(
       new (&allocator_) HNeg(Primitive::kPrimInt, k_body), 0);
   PerformInductionVarAnalysis();
 
@@ -563,7 +602,7 @@
     k[d] = InsertLoopPhi(0, d);
   }
 
-  HInstruction *inc = InsertInstruction(
+  HInstruction* inc = InsertInstruction(
       new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k[9]), 9);
   HInstruction* store = InsertArrayStore(inc, 9);
 
@@ -597,7 +636,7 @@
   //   a[i] = 0;
   // }
   BuildLoopNest(1);
-  HInstruction *conv = InsertInstruction(
+  HInstruction* conv = InsertInstruction(
       new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
   HInstruction* store1 = InsertArrayStore(conv, 0);
   HInstruction* store2 = InsertArrayStore(basic_[0], 0);
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index cd8b7c7..140c7f0 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -525,6 +525,8 @@
             return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
           case HInductionVarAnalysis::kDiv:
             return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
+          case HInductionVarAnalysis::kXor:
+            return GetXor(info->op_a, info->op_b);
           case HInductionVarAnalysis::kFetch:
             return GetFetch(info->fetch, trip, in_body, is_min);
           case HInductionVarAnalysis::kTripCountInLoop:
@@ -626,6 +628,21 @@
   return Value();
 }
 
+InductionVarRange::Value InductionVarRange::GetXor(
+    HInductionVarAnalysis::InductionInfo* info1,
+    HInductionVarAnalysis::InductionInfo* info2) const {
+  int64_t v1 = 0;
+  int64_t v2 = 0;
+  // Only accept exact values.
+  if (IsConstant(info1, kExact, &v1) && IsConstant(info2, kExact, &v2)) {
+    int64_t value = v1 ^ v2;
+    if (CanLongValueFitIntoInt(value)) {
+      return Value(static_cast<int32_t>(value));
+    }
+  }
+  return Value();
+}
+
 InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
     int64_t value,
     HInductionVarAnalysis::InductionInfo* info,
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index df31e81..8951300 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -193,6 +193,8 @@
                HInductionVarAnalysis::InductionInfo* trip,
                bool in_body,
                bool is_min) const;
+  Value GetXor(HInductionVarAnalysis::InductionInfo* info1,
+               HInductionVarAnalysis::InductionInfo* info2) const;
 
   Value MulRangeAndConstant(int64_t value,
                             HInductionVarAnalysis::InductionInfo* info,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 640787c..770a55d 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -47,6 +47,7 @@
 #include "gc/collector/semi_space.h"
 #include "gc/collector/sticky_mark_sweep.h"
 #include "gc/reference_processor.h"
+#include "gc/scoped_gc_critical_section.h"
 #include "gc/space/bump_pointer_space.h"
 #include "gc/space/dlmalloc_space-inl.h"
 #include "gc/space/image_space.h"
@@ -1370,6 +1371,8 @@
     // Deflate the monitors, this can cause a pause but shouldn't matter since we don't care
     // about pauses.
     ScopedTrace trace("Deflating monitors");
+    // Avoid race conditions on the lock word for CC.
+    ScopedGCCriticalSection gcs(self, kGcCauseTrim, kCollectorTypeHeapTrim);
     ScopedSuspendAll ssa(__FUNCTION__);
     uint64_t start_time = NanoTime();
     size_t count = runtime->GetMonitorList()->DeflateMonitors();
@@ -4193,7 +4196,7 @@
   AllocationListener* old = GetAndOverwriteAllocationListener(&alloc_listener_, nullptr);
 
   if (old != nullptr) {
-    Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
+    Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
   }
 }
 
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index 7e4ee84..450f85e 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -133,6 +133,8 @@
     DCHECK_EQ(self, art::Thread::Current());
 
     if (handler_->IsEventEnabledAnywhere(JVMTI_EVENT_VM_OBJECT_ALLOC)) {
+      art::StackHandleScope<1> hs(self);
+      auto h = hs.NewHandleWrapper(obj);
       // jvmtiEventVMObjectAlloc parameters:
       //      jvmtiEnv *jvmti_env,
       //      JNIEnv* jni_env,
diff --git a/test/530-checker-loops2/src/Main.java b/test/530-checker-loops2/src/Main.java
index 7acf008..dca00bd 100644
--- a/test/530-checker-loops2/src/Main.java
+++ b/test/530-checker-loops2/src/Main.java
@@ -111,6 +111,24 @@
     return result;
   }
 
+  /// CHECK-START: int Main.periodicXorSequence(int) BCE (before)
+  /// CHECK-DAG: BoundsCheck
+  //
+  /// CHECK-START: int Main.periodicXorSequence(int) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK-NOT: Deoptimize
+  private static int periodicXorSequence(int tc) {
+    int[] x = { 1, 3 };
+    // Loop with periodic sequence (0, 1).
+    int k = 0;
+    int result = 0;
+    for (int i = 0; i < tc; i++) {
+      result += x[k];
+      k ^= 1;
+    }
+    return result;
+  }
+
   /// CHECK-START: int Main.justRightUp1() BCE (before)
   /// CHECK-DAG: BoundsCheck
   //
@@ -895,8 +913,9 @@
     expectEquals(0, periodicIdiom(-1));
     for (int tc = 0; tc < 32; tc++) {
       int expected = (tc >> 1) << 2;
-      if ((tc & 1) != 0)
+      if ((tc & 1) != 0) {
         expected += 1;
+      }
       expectEquals(expected, periodicIdiom(tc));
     }
 
@@ -904,8 +923,9 @@
     expectEquals(0, periodicSequence2(-1));
     for (int tc = 0; tc < 32; tc++) {
       int expected = (tc >> 1) << 2;
-      if ((tc & 1) != 0)
+      if ((tc & 1) != 0) {
         expected += 1;
+      }
       expectEquals(expected, periodicSequence2(tc));
     }
 
@@ -915,6 +935,16 @@
       expectEquals(tc * 16, periodicSequence4(tc));
     }
 
+    // Periodic adds (1, 3), one at the time.
+    expectEquals(0, periodicXorSequence(-1));
+    for (int tc = 0; tc < 32; tc++) {
+      int expected = (tc >> 1) << 2;
+      if ((tc & 1) != 0) {
+        expected += 1;
+      }
+      expectEquals(expected, periodicXorSequence(tc));
+    }
+
     // Large bounds.
     expectEquals(55, justRightUp1());
     expectEquals(55, justRightUp2());
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 29000f0..1a0f78e 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -263,7 +263,7 @@
 # 147-stripped-dex-fallback isn't supported on device because --strip-dex
 # requires the zip command.
 # 569-checker-pattern-replacement tests behaviour present only on host.
-# 90{2,3,4,5} are not supported in current form due to linker
+# 90{2,3,4,5,6} are not supported in current form due to linker
 # restrictions. See b/31681198
 TEST_ART_BROKEN_TARGET_TESTS := \
   147-stripped-dex-fallback \
@@ -272,6 +272,7 @@
   903-hello-tagging \
   904-object-allocation \
   905-object-free \
+  906-iterate-heap \
 
 ifneq (,$(filter target,$(TARGET_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \