diff a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp
--- a/src/hotspot/share/opto/loopnode.hpp
+++ b/src/hotspot/share/opto/loopnode.hpp
@@ -41,10 +41,11 @@
 class Node;
 class OuterStripMinedLoopEndNode;
 class PredicateBlock;
 class PathFrequency;
 class PhaseIdealLoop;
+class UnswitchCandidate;
 class UnswitchedLoopSelector;
 class VectorSet;
 class VSharedData;
 class Invariance;
 struct small_cache;
@@ -77,11 +78,12 @@
          HasAtomicPostLoop     = 1<<11,
          StripMined            = 1<<12,
          SubwordLoop           = 1<<13,
          ProfileTripFailed     = 1<<14,
          LoopNestInnerLoop     = 1<<15,
-         LoopNestLongOuterLoop = 1<<16 };
+         LoopNestLongOuterLoop = 1<<16,
+         FlatArrays            = 1<<17};
   char _unswitch_count;
   enum { _unswitch_max=3 };
 
   // Expected trip count from profile data
   float _profile_trip_cnt;
@@ -100,10 +102,11 @@
   bool is_strip_mined() const { return _loop_flags & StripMined; }
   bool is_profile_trip_failed() const { return _loop_flags & ProfileTripFailed; }
   bool is_subword_loop() const { return _loop_flags & SubwordLoop; }
   bool is_loop_nest_inner_loop() const { return _loop_flags & LoopNestInnerLoop; }
   bool is_loop_nest_outer_loop() const { return _loop_flags & LoopNestLongOuterLoop; }
+  bool is_flat_arrays() const { return _loop_flags & FlatArrays; }
 
   void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; }
   void mark_was_slp() { _loop_flags |= WasSlpAnalyzed; }
   void mark_passed_slp() { _loop_flags |= PassedSlpAnalysis; }
   void mark_do_unroll_only() { _loop_flags |= DoUnrollOnly; }
@@ -113,10 +116,11 @@
   void clear_strip_mined() { _loop_flags &= ~StripMined; }
   void mark_profile_trip_failed() { _loop_flags |= ProfileTripFailed; }
   void mark_subword_loop() { _loop_flags |= SubwordLoop; }
   void mark_loop_nest_inner_loop() { _loop_flags |= LoopNestInnerLoop; }
   void mark_loop_nest_outer_loop() { _loop_flags |= LoopNestLongOuterLoop; }
+  void mark_flat_arrays() { _loop_flags |= FlatArrays; }
 
   int unswitch_max() { return _unswitch_max; }
   int unswitch_count() { return _unswitch_count; }
 
   void set_unswitch_count(int val) {
@@ -688,10 +692,11 @@
   bool policy_peel_only( PhaseIdealLoop *phase ) const;
 
   // Return TRUE or FALSE if the loop should be unswitched -- clone
   // loop with an invariant test
   bool policy_unswitching( PhaseIdealLoop *phase ) const;
+  bool no_unswitch_candidate() const;
 
   // Micro-benchmark spamming.  Remove empty loops.
   bool do_remove_empty_loop( PhaseIdealLoop *phase );
 
   // Convert one iteration loop into normal code.
@@ -1428,25 +1433,27 @@
   // Clone loop with an invariant test (that does not exit) and
   // insert a clone of the test that selects which version to
   // execute.
   void do_unswitching(IdealLoopTree* loop, Node_List& old_new);
 
-  IfNode* find_unswitch_candidate(const IdealLoopTree* loop) const;
+  IfNode* find_unswitch_candidates(const IdealLoopTree* loop, Node_List& flat_array_checks) const;
+  IfNode* find_unswitch_candidate_from_idoms(const IdealLoopTree* loop) const;
 
  private:
   static bool has_control_dependencies_from_predicates(LoopNode* head);
   static void revert_to_normal_loop(const LoopNode* loop_head);
 
   void hoist_invariant_check_casts(const IdealLoopTree* loop, const Node_List& old_new,
-                                   const UnswitchedLoopSelector& unswitched_loop_selector);
+                                   const UnswitchCandidate& unswitch_candidate, const IfNode* loop_selector);
   void add_unswitched_loop_version_bodies_to_igvn(IdealLoopTree* loop, const Node_List& old_new);
   static void increment_unswitch_counts(LoopNode* original_head, LoopNode* new_head);
   void remove_unswitch_candidate_from_loops(const Node_List& old_new, const UnswitchedLoopSelector& unswitched_loop_selector);
 #ifndef PRODUCT
   static void trace_loop_unswitching_count(IdealLoopTree* loop, LoopNode* original_head);
   static void trace_loop_unswitching_impossible(const LoopNode* original_head);
   static void trace_loop_unswitching_result(const UnswitchedLoopSelector& unswitched_loop_selector,
+                                            const UnswitchCandidate& unswitch_candidate,
                                             const LoopNode* original_head, const LoopNode* new_head);
 #endif
 
  public:
 
@@ -1577,11 +1584,13 @@
   bool split_up( Node *n, Node *blk1, Node *blk2 );
 
   Node* place_outside_loop(Node* useblock, IdealLoopTree* loop) const;
   Node* try_move_store_before_loop(Node* n, Node *n_ctrl);
   void try_move_store_after_loop(Node* n);
+  void move_flat_array_check_out_of_loop(Node* n);
   bool identical_backtoback_ifs(Node *n);
+  bool flat_array_element_type_check(Node *n);
   bool can_split_if(Node *n_ctrl);
   bool cannot_split_division(const Node* n, const Node* region) const;
   static bool is_divisor_loop_phi(const Node* divisor, const Node* loop);
   bool loop_phi_backedge_type_contains_zero(const Node* phi_divisor, const Type* zero) const;
 
@@ -1787,10 +1796,12 @@
 
   bool can_move_to_inner_loop(Node* n, LoopNode* n_loop, Node* x);
 
   void pin_array_access_nodes_dependent_on(Node* ctrl);
 
+  void collect_flat_array_checks(const IdealLoopTree* loop, Node_List& flat_array_checks) const;
+
   Node* ensure_node_and_inputs_are_above_pre_end(CountedLoopEndNode* pre_end, Node* node);
 };
 
 
 class AutoNodeBudget : public StackObj
