changeset 23806:4653aff04861

Merge
author asaha
date Fri, 05 Feb 2016 09:28:57 -0800
parents c5075f52f88a (current diff) d992b4af24c7 (diff)
children 2b2511bd3cc8
files
diffstat 25 files changed, 844 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java	Mon Feb 01 16:28:45 2016 -0800
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -219,7 +219,7 @@
     if (threadNameField == null) {
       SystemDictionary sysDict = VM.getVM().getSystemDictionary();
       InstanceKlass k = sysDict.getThreadKlass();
-      threadNameField  = (OopField) k.findField("name", "[C");
+      threadNameField  = (OopField) k.findField("name", "Ljava/lang/String;");
       threadGroupField = (OopField) k.findField("group", "Ljava/lang/ThreadGroup;");
       threadEETopField = (LongField) k.findField("eetop", "J");
       threadTIDField = (LongField) k.findField("tid", "J");
@@ -258,7 +258,7 @@
 
   public static String threadOopGetName(Oop threadOop) {
     initThreadFields();
-    return charArrayToString((TypeArray) threadNameField.getValue(threadOop));
+    return stringOopToString(threadNameField.getValue(threadOop));
   }
 
   /** May return null if, e.g., thread was not started */
--- a/src/share/vm/classfile/javaClasses.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/classfile/javaClasses.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -936,7 +936,7 @@
   assert(_group_offset == 0, "offsets should be initialized only once");
 
   Klass* k = SystemDictionary::Thread_klass();
-  compute_offset(_name_offset,      k, vmSymbols::name_name(),      vmSymbols::char_array_signature());
+  compute_offset(_name_offset,      k, vmSymbols::name_name(),      vmSymbols::string_signature());
   compute_offset(_group_offset,     k, vmSymbols::group_name(),     vmSymbols::threadgroup_signature());
   compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), vmSymbols::classloader_signature());
   compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), vmSymbols::accesscontrolcontext_signature());
@@ -966,15 +966,12 @@
 }
 
 
-typeArrayOop java_lang_Thread::name(oop java_thread) {
-  oop name = java_thread->obj_field(_name_offset);
-  assert(name == NULL || (name->is_typeArray() && TypeArrayKlass::cast(name->klass())->element_type() == T_CHAR), "just checking");
-  return typeArrayOop(name);
-}
-
-
-void java_lang_Thread::set_name(oop java_thread, typeArrayOop name) {
-  assert(java_thread->obj_field(_name_offset) == NULL, "name should be NULL");
+oop java_lang_Thread::name(oop java_thread) {
+  return java_thread->obj_field(_name_offset);
+}
+
+
+void java_lang_Thread::set_name(oop java_thread, oop name) {
   java_thread->obj_field_put(_name_offset, name);
 }
 
--- a/src/share/vm/classfile/javaClasses.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/classfile/javaClasses.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -343,8 +343,8 @@
   // Set JavaThread for instance
   static void set_thread(oop java_thread, JavaThread* thread);
   // Name
-  static typeArrayOop name(oop java_thread);
-  static void set_name(oop java_thread, typeArrayOop name);
+  static oop name(oop java_thread);
+  static void set_name(oop java_thread, oop name);
   // Priority
   static ThreadPriority priority(oop java_thread);
   static void set_priority(oop java_thread, ThreadPriority priority);
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -3839,6 +3839,16 @@
   _surviving_young_words = NULL;
 }
 
+class VerifyRegionRemSetClosure : public HeapRegionClosure {
+  public:
+    bool doHeapRegion(HeapRegion* hr) {
+      if (!hr->continuesHumongous()) {
+        hr->verify_rem_set();
+      }
+      return false;
+    }
+};
+
 #ifdef ASSERT
 class VerifyCSetClosure: public HeapRegionClosure {
 public:
@@ -4015,6 +4025,14 @@
       increment_total_collections(false /* full gc */);
       increment_gc_time_stamp();
 
+      if (VerifyRememberedSets) {
+        if (!VerifySilently) {
+          gclog_or_tty->print_cr("[Verifying RemSets before GC]");
+        }
+        VerifyRegionRemSetClosure v_cl;
+        heap_region_iterate(&v_cl);
+      }
+
       verify_before_gc();
       check_bitmaps("GC Start");
 
@@ -4246,6 +4264,14 @@
         // scanning cards (see CR 7039627).
         increment_gc_time_stamp();
 
+        if (VerifyRememberedSets) {
+          if (!VerifySilently) {
+            gclog_or_tty->print_cr("[Verifying RemSets after GC]");
+          }
+          VerifyRegionRemSetClosure v_cl;
+          heap_region_iterate(&v_cl);
+        }
+
         verify_after_gc();
         check_bitmaps("GC End");
 
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -639,8 +639,8 @@
   G1OffsetTableContigSpace::print_on(st);
 }
 
-class VerifyLiveClosure: public OopClosure {
-private:
+class G1VerificationClosure : public OopClosure {
+protected:
   G1CollectedHeap* _g1h;
   CardTableModRefBS* _bs;
   oop _containing_obj;
@@ -651,7 +651,7 @@
   // _vo == UsePrevMarking -> use "prev" marking information,
   // _vo == UseNextMarking -> use "next" marking information,
   // _vo == UseMarkWord    -> use mark word from object header.
-  VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) :
+  G1VerificationClosure(G1CollectedHeap* g1h, VerifyOption vo) :
     _g1h(g1h), _bs(NULL), _containing_obj(NULL),
     _failures(false), _n_failures(0), _vo(vo)
   {
@@ -667,9 +667,6 @@
   bool failures() { return _failures; }
   int n_failures() { return _n_failures; }
 
-  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
-  virtual void do_oop(      oop* p) { do_oop_work(p); }
-
   void print_object(outputStream* out, oop obj) {
 #ifdef PRODUCT
     Klass* k = obj->klass();
@@ -679,19 +676,31 @@
     obj->print_on(out);
 #endif // PRODUCT
   }
+};
+
+class VerifyLiveClosure : public G1VerificationClosure {
+public:
+  VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {}
+  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+  virtual void do_oop(oop* p) { do_oop_work(p); }
 
   template <class T>
   void do_oop_work(T* p) {
     assert(_containing_obj != NULL, "Precondition");
     assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
-           "Precondition");
+      "Precondition");
+    verify_liveness(p);
+  }
+
+  template <class T>
+  void verify_liveness(T* p) {
     T heap_oop = oopDesc::load_heap_oop(p);
     if (!oopDesc::is_null(heap_oop)) {
       oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
       bool failed = false;
       if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) {
         MutexLockerEx x(ParGCRareEvent_lock,
-                        Mutex::_no_safepoint_check_flag);
+          Mutex::_no_safepoint_check_flag);
 
         if (!_failures) {
           gclog_or_tty->cr();
@@ -727,50 +736,71 @@
         failed = true;
         _n_failures++;
       }
+    }
+  }
+};
 
-      if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
-        HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
-        HeapRegion* to   = _g1h->heap_region_containing(obj);
-        if (from != NULL && to != NULL &&
-            from != to &&
-            !to->isHumongous()) {
-          jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
-          jbyte cv_field = *_bs->byte_for_const(p);
-          const jbyte dirty = CardTableModRefBS::dirty_card_val();
+class VerifyRemSetClosure : public G1VerificationClosure {
+public:
+  VerifyRemSetClosure(G1CollectedHeap* g1h, VerifyOption vo) : G1VerificationClosure(g1h, vo) {}
+  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+  virtual void do_oop(oop* p) { do_oop_work(p); }
+
+  template <class T>
+  void do_oop_work(T* p) {
+    assert(_containing_obj != NULL, "Precondition");
+    assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
+      "Precondition");
+    verify_remembered_set(p);
+  }
 
-          bool is_bad = !(from->is_young()
-                          || to->rem_set()->contains_reference(p)
-                          || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
-                              (_containing_obj->is_objArray() ?
-                                  cv_field == dirty
-                               : cv_obj == dirty || cv_field == dirty));
-          if (is_bad) {
-            MutexLockerEx x(ParGCRareEvent_lock,
-                            Mutex::_no_safepoint_check_flag);
+  template <class T>
+  void verify_remembered_set(T* p) {
+    T heap_oop = oopDesc::load_heap_oop(p);
+    if (!oopDesc::is_null(heap_oop)) {
+      oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
+      bool failed = false;
+      HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
+      HeapRegion* to   = _g1h->heap_region_containing(obj);
+      if (from != NULL && to != NULL &&
+          from != to &&
+          !to->isHumongous()) {
+        jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
+        jbyte cv_field = *_bs->byte_for_const(p);
+        const jbyte dirty = CardTableModRefBS::dirty_card_val();
 
-            if (!_failures) {
-              gclog_or_tty->cr();
-              gclog_or_tty->print_cr("----------");
-            }
-            gclog_or_tty->print_cr("Missing rem set entry:");
-            gclog_or_tty->print_cr("Field "PTR_FORMAT" "
-                                   "of obj "PTR_FORMAT", "
-                                   "in region "HR_FORMAT,
-                                   p, (void*) _containing_obj,
-                                   HR_FORMAT_PARAMS(from));
-            _containing_obj->print_on(gclog_or_tty);
-            gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
-                                   "in region "HR_FORMAT,
-                                   (void*) obj,
-                                   HR_FORMAT_PARAMS(to));
-            obj->print_on(gclog_or_tty);
-            gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
-                          cv_obj, cv_field);
+        bool is_bad = !(from->is_young()
+                        || to->rem_set()->contains_reference(p)
+                        || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
+                            (_containing_obj->is_objArray() ?
+                                cv_field == dirty
+                             : cv_obj == dirty || cv_field == dirty));
+        if (is_bad) {
+          MutexLockerEx x(ParGCRareEvent_lock,
+                          Mutex::_no_safepoint_check_flag);
+
+          if (!_failures) {
+            gclog_or_tty->cr();
             gclog_or_tty->print_cr("----------");
-            gclog_or_tty->flush();
-            _failures = true;
-            if (!failed) _n_failures++;
           }
+          gclog_or_tty->print_cr("Missing rem set entry:");
+          gclog_or_tty->print_cr("Field "PTR_FORMAT" "
+                                 "of obj "PTR_FORMAT", "
+                                 "in region "HR_FORMAT,
+                                 p, (void*) _containing_obj,
+                                 HR_FORMAT_PARAMS(from));
+          _containing_obj->print_on(gclog_or_tty);
+          gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
+                                 "in region "HR_FORMAT,
+                                 (void*) obj,
+                                 HR_FORMAT_PARAMS(to));
+          obj->print_on(gclog_or_tty);
+          gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
+                        cv_obj, cv_field);
+          gclog_or_tty->print_cr("----------");
+          gclog_or_tty->flush();
+          _failures = true;
+          if (!failed) _n_failures++;
         }
       }
     }
@@ -787,6 +817,7 @@
   HeapWord* p = bottom();
   HeapWord* prev_p = NULL;
   VerifyLiveClosure vl_cl(g1, vo);
+  VerifyRemSetClosure vr_cl(g1, vo);
   bool is_humongous = isHumongous();
   bool do_bot_verify = !is_young();
   size_t object_num = 0;
@@ -832,7 +863,23 @@
           return;
         } else {
           vl_cl.set_containing_obj(obj);
-          obj->oop_iterate_no_header(&vl_cl);
+          if (!g1->full_collection() || G1VerifyRSetsDuringFullGC) {
+            // verify liveness and rem_set
+            vr_cl.set_containing_obj(obj);
+            G1Mux2Closure mux(&vl_cl, &vr_cl);
+            obj->oop_iterate_no_header(&mux);
+
+            if (vr_cl.failures()) {
+              *failures = true;
+            }
+            if (G1MaxVerifyFailures >= 0 &&
+              vr_cl.n_failures() >= G1MaxVerifyFailures) {
+              return;
+            }
+          } else {
+            // verify only liveness
+            obj->oop_iterate_no_header(&vl_cl);
+          }
           if (vl_cl.failures()) {
             *failures = true;
           }
@@ -842,7 +889,7 @@
           }
         }
       } else {
-        gclog_or_tty->print_cr(PTR_FORMAT" no an oop", (void *)obj);
+        gclog_or_tty->print_cr(PTR_FORMAT" not an oop", (void *)obj);
         *failures = true;
         return;
       }
@@ -930,6 +977,46 @@
   verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);
 }
 
+void HeapRegion::verify_rem_set(VerifyOption vo, bool* failures) const {
+  G1CollectedHeap* g1 = G1CollectedHeap::heap();
+  *failures = false;
+  HeapWord* p = bottom();
+  HeapWord* prev_p = NULL;
+  VerifyRemSetClosure vr_cl(g1, vo);
+  while (p < top()) {
+    oop obj = oop(p);
+    size_t obj_size = block_size(p);
+
+    if (!g1->is_obj_dead_cond(obj, this, vo)) {
+      if (obj->is_oop()) {
+        vr_cl.set_containing_obj(obj);
+        obj->oop_iterate_no_header(&vr_cl);
+
+        if (vr_cl.failures()) {
+          *failures = true;
+        }
+        if (G1MaxVerifyFailures >= 0 &&
+          vr_cl.n_failures() >= G1MaxVerifyFailures) {
+          return;
+        }
+      } else {
+        gclog_or_tty->print_cr(PTR_FORMAT " not an oop", p2i(obj));
+        *failures = true;
+        return;
+      }
+    }
+
+    prev_p = p;
+    p += obj_size;
+  }
+}
+
+void HeapRegion::verify_rem_set() const {
+  bool failures = false;
+  verify_rem_set(VerifyOption_G1UsePrevMarking, &failures);
+  guarantee(!failures, "HeapRegion RemSet verification failed");
+}
+
 // G1OffsetTableContigSpace code; copied from space.cpp.  Hope this can go
 // away eventually.
 
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -779,6 +779,9 @@
 
   // Override; it uses the "prev" marking information
   virtual void verify() const;
+
+  void verify_rem_set(VerifyOption vo, bool *failures) const;
+  void verify_rem_set() const;
 };
 
 // HeapRegionClosure is used for iterating over regions.
--- a/src/share/vm/opto/compile.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/compile.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -412,6 +412,13 @@
       remove_macro_node(n);
     }
   }
+  // Remove useless CastII nodes with range check dependency
+  for (int i = range_check_cast_count() - 1; i >= 0; i--) {
+    Node* cast = range_check_cast_node(i);
+    if (!useful.member(cast)) {
+      remove_range_check_cast(cast);
+    }
+  }
   // Remove useless expensive node
   for (int i = C->expensive_count()-1; i >= 0; i--) {
     Node* n = C->expensive_node(i);
@@ -1148,6 +1155,7 @@
   _macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
+  _range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   register_library_intrinsics();
 }
 
@@ -1876,6 +1884,22 @@
   assert(predicate_count()==0, "should be clean!");
 }
 
+void Compile::add_range_check_cast(Node* n) {
+  assert(n->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+  assert(!_range_check_casts->contains(n), "duplicate entry in range check casts");
+  _range_check_casts->append(n);
+}
+
+// Remove all range check dependent CastIINodes.
+void Compile::remove_range_check_casts(PhaseIterGVN &igvn) {
+  for (int i = range_check_cast_count(); i > 0; i--) {
+    Node* cast = range_check_cast_node(i-1);
+    assert(cast->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+    igvn.replace_node(cast, cast->in(1));
+  }
+  assert(range_check_cast_count() == 0, "should be empty");
+}
+
 // StringOpts and late inlining of string methods
 void Compile::inline_string_calls(bool parse_time) {
   {
@@ -2218,6 +2242,12 @@
     PhaseIdealLoop::verify(igvn);
   }
 
+  if (range_check_cast_count() > 0) {
+    // No more loop optimizations. Remove all range check dependent CastIINodes.
+    C->remove_range_check_casts(igvn);
+    igvn.optimize();
+  }
+
   {
     NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); )
     PhaseMacroExpand  mex(igvn);
@@ -2987,6 +3017,16 @@
 
 #endif
 
+#ifdef ASSERT
+  case Op_CastII:
+    // Verify that all range check dependent CastII nodes were removed.
+    if (n->isa_CastII()->has_range_check()) {
+      n->dump(3);
+      assert(false, "Range check dependent CastII node was not removed");
+    }
+    break;
+#endif
+
   case Op_ModI:
     if (UseDivMod) {
       // Check if a%b and a/b both exist
@@ -4024,6 +4064,24 @@
   }
 }
 
+// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
+  if (ctrl != NULL) {
+    // Express control dependency by a CastII node with a narrow type.
+    value = new (phase->C) CastIINode(value, itype, false, true /* range check dependency */);
+    // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
+    // node from floating above the range check during loop optimizations. Otherwise, the
+    // ConvI2L node may be eliminated independently of the range check, causing the data path
+    // to become TOP while the control path is still there (although it's unreachable).
+    value->set_req(0, ctrl);
+    // Save CastII node to remove it after loop optimizations.
+    phase->C->add_range_check_cast(value);
+    value = phase->transform(value);
+  }
+  const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen);
+  return phase->transform(new (phase->C) ConvI2LNode(value, ltype));
+}
+
 // Auxiliary method to support randomized stressing/fuzzing.
 //
 // This method can be called the arbitrary number of times, with current count
--- a/src/share/vm/opto/compile.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/compile.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -75,6 +75,7 @@
 class JVMState;
 class Type;
 class TypeData;
+class TypeInt;
 class TypePtr;
 class TypeOopPtr;
 class TypeFunc;
@@ -334,6 +335,7 @@
   GrowableArray<Node*>* _macro_nodes;           // List of nodes which need to be expanded before matching.
   GrowableArray<Node*>* _predicate_opaqs;       // List of Opaque1 nodes for the loop predicates.
   GrowableArray<Node*>* _expensive_nodes;       // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
+  GrowableArray<Node*>* _range_check_casts;     // List of CastII nodes with a range check dependency
   ConnectionGraph*      _congraph;
 #ifndef PRODUCT
   IdealGraphPrinter*    _printer;
@@ -669,7 +671,7 @@
   void set_congraph(ConnectionGraph* congraph)  { _congraph = congraph;}
   void add_macro_node(Node * n) {
     //assert(n->is_macro(), "must be a macro node");
-    assert(!_macro_nodes->contains(n), " duplicate entry in expand list");
+    assert(!_macro_nodes->contains(n), "duplicate entry in expand list");
     _macro_nodes->append(n);
   }
   void remove_macro_node(Node * n) {
@@ -689,10 +691,23 @@
     }
   }
   void add_predicate_opaq(Node * n) {
-    assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1");
+    assert(!_predicate_opaqs->contains(n), "duplicate entry in predicate opaque1");
     assert(_macro_nodes->contains(n), "should have already been in macro list");
     _predicate_opaqs->append(n);
   }
+
+  // Range check dependent CastII nodes that can be removed after loop optimizations
+  void add_range_check_cast(Node* n);
+  void remove_range_check_cast(Node* n) {
+    if (_range_check_casts->contains(n)) {
+      _range_check_casts->remove(n);
+    }
+  }
+  Node* range_check_cast_node(int idx) const { return _range_check_casts->at(idx);  }
+  int   range_check_cast_count()       const { return _range_check_casts->length(); }
+  // Remove all range check dependent CastIINodes.
+  void  remove_range_check_casts(PhaseIterGVN &igvn);
+
   // remove the opaque nodes that protect the predicates so that the unused checks and
   // uncommon traps will be eliminated from the graph.
   void cleanup_loop_predicates(PhaseIterGVN &igvn);
@@ -1201,6 +1216,9 @@
   // Definitions of pd methods
   static void pd_compiler2_init();
 
+  // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+  static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
+
   // Auxiliary method for randomized fuzzing/stressing
   static bool randomized_select(int count);
 };
--- a/src/share/vm/opto/connode.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/connode.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -535,6 +535,9 @@
   if (_carry_dependency) {
     st->print(" carry dependency");
   }
+  if (_range_check_dependency) {
+    st->print(" range check dependency");
+  }
 }
 #endif
 
@@ -994,7 +997,8 @@
   }
 
 #ifdef _LP64
-  // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) ,
+  // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or
+  // ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))),
   // but only if x and y have subranges that cannot cause 32-bit overflow,
   // under the assumption that x+y is in my own subrange this->type().
 
@@ -1018,6 +1022,13 @@
 
   Node* z = in(1);
   int op = z->Opcode();
+  Node* ctrl = NULL;
+  if (op == Op_CastII && z->as_CastII()->has_range_check()) {
+    // Skip CastII node but save control dependency
+    ctrl = z->in(0);
+    z = z->in(1);
+    op = z->Opcode();
+  }
   if (op == Op_AddI || op == Op_SubI) {
     Node* x = z->in(1);
     Node* y = z->in(2);
@@ -1075,9 +1086,10 @@
       rylo = -ryhi;
       ryhi = -rylo0;
     }
-
-    Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) );
-    Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) );
+    assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow");
+    assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow");
+    Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl);
+    Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl);
     switch (op) {
     case Op_AddI:  return new (phase->C) AddLNode(cx, cy);
     case Op_SubI:  return new (phase->C) SubLNode(cx, cy);
--- a/src/share/vm/opto/connode.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/connode.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -244,19 +244,31 @@
   private:
   // Can this node be removed post CCP or does it carry a required dependency?
   const bool _carry_dependency;
+  // Is this node dependent on a range check?
+  const bool _range_check_dependency;
 
   protected:
   virtual uint cmp( const Node &n ) const;
   virtual uint size_of() const;
 
 public:
-  CastIINode(Node *n, const Type *t, bool carry_dependency = false)
-    : ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {}
+  CastIINode(Node *n, const Type *t, bool carry_dependency = false, bool range_check_dependency = false)
+    : ConstraintCastNode(n,t), _carry_dependency(carry_dependency), _range_check_dependency(range_check_dependency) {
+    init_class_id(Class_CastII);
+  }
   virtual int Opcode() const;
   virtual uint ideal_reg() const { return Op_RegI; }
   virtual Node *Identity( PhaseTransform *phase );
   virtual const Type *Value( PhaseTransform *phase ) const;
   virtual Node *Ideal_DU_postCCP( PhaseCCP * );
+  const bool has_range_check() {
+ #ifdef _LP64
+     return _range_check_dependency;
+ #else
+     assert(!_range_check_dependency, "Should not have range check dependency");
+     return false;
+ #endif
+   }
 #ifndef PRODUCT
   virtual void dump_spec(outputStream *st) const;
 #endif
--- a/src/share/vm/opto/graphKit.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/graphKit.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1645,7 +1645,7 @@
 
 //-------------------------array_element_address-------------------------
 Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
-                                      const TypeInt* sizetype) {
+                                      const TypeInt* sizetype, Node* ctrl) {
   uint shift  = exact_log2(type2aelembytes(elembt));
   uint header = arrayOopDesc::base_offset_in_bytes(elembt);
 
@@ -1670,9 +1670,9 @@
   // number.  (The prior range check has ensured this.)
   // This assertion is used by ConvI2LNode::Ideal.
   int index_max = max_jint - 1;  // array size is max_jint, index is one less
-  if (sizetype != NULL)  index_max = sizetype->_hi - 1;
-  const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax);
-  idx = _gvn.transform( new (C) ConvI2LNode(idx, lidxtype) );
+  if (sizetype != NULL) index_max = sizetype->_hi - 1;
+  const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax);
+  idx = C->constrained_convI2L(&_gvn, idx, iidxtype, ctrl);
 #endif
   Node* scale = _gvn.transform( new (C) LShiftXNode(idx, intcon(shift)) );
   return basic_plus_adr(ary, base, scale);
@@ -3491,10 +3491,6 @@
 
   Node* initial_slow_cmp  = _gvn.transform( new (C) CmpUNode( length, intcon( fast_size_limit ) ) );
   Node* initial_slow_test = _gvn.transform( new (C) BoolNode( initial_slow_cmp, BoolTest::gt ) );
-  if (initial_slow_test->is_Bool()) {
-    // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
-    initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
-  }
 
   // --- Size Computation ---
   // array_size = round_to_heap(array_header + (length << elem_shift));
@@ -3540,13 +3536,35 @@
   Node* lengthx = ConvI2X(length);
   Node* headerx = ConvI2X(header_size);
 #ifdef _LP64
-  { const TypeLong* tllen = _gvn.find_long_type(lengthx);
-    if (tllen != NULL && tllen->_lo < 0) {
+  { const TypeInt* tilen = _gvn.find_int_type(length);
+    if (tilen != NULL && tilen->_lo < 0) {
       // Add a manual constraint to a positive range.  Cf. array_element_address.
-      jlong size_max = arrayOopDesc::max_array_length(T_BYTE);
-      if (size_max > tllen->_hi)  size_max = tllen->_hi;
-      const TypeLong* tlcon = TypeLong::make(CONST64(0), size_max, Type::WidenMin);
-      lengthx = _gvn.transform( new (C) ConvI2LNode(length, tlcon));
+      jlong size_max = fast_size_limit;
+      if (size_max > tilen->_hi)  size_max = tilen->_hi;
+      const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin);
+
+      // Only do a narrow I2L conversion if the range check passed.
+      IfNode* iff = new (C) IfNode(control(), initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
+      _gvn.transform(iff);
+      RegionNode* region = new (C) RegionNode(3);
+      _gvn.set_type(region, Type::CONTROL);
+      lengthx = new (C) PhiNode(region, TypeLong::LONG);
+      _gvn.set_type(lengthx, TypeLong::LONG);
+
+      // Range check passed. Use ConvI2L node with narrow type.
+      Node* passed = IfFalse(iff);
+      region->init_req(1, passed);
+      // Make I2L conversion control dependent to prevent it from
+      // floating above the range check during loop optimizations.
+      lengthx->init_req(1, C->constrained_convI2L(&_gvn, length, tlcon, passed));
+
+      // Range check failed. Use ConvI2L with wide type because length may be invalid.
+      region->init_req(2, IfTrue(iff));
+      lengthx->init_req(2, ConvI2X(length));
+
+      set_control(region);
+      record_for_igvn(region);
+      record_for_igvn(lengthx);
     }
   }
 #endif
@@ -3577,6 +3595,11 @@
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
+  if (initial_slow_test->is_Bool()) {
+    // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
+    initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
+  }
+
   // Create the AllocateArrayNode and its result projections
   AllocateArrayNode* alloc
     = new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
--- a/src/share/vm/opto/graphKit.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/graphKit.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -626,7 +626,9 @@
   // Return addressing for an array element.
   Node* array_element_address(Node* ary, Node* idx, BasicType elembt,
                               // Optional constraint on the array size:
-                              const TypeInt* sizetype = NULL);
+                              const TypeInt* sizetype = NULL,
+                              // Optional control dependency (for example, on range check)
+                              Node* ctrl = NULL);
 
   // Return a load of array element at idx.
   Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype);
--- a/src/share/vm/opto/loopTransform.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/loopTransform.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -2438,7 +2438,7 @@
 
 //=============================================================================
 // Process all the loops in the loop tree and replace any fill
-// patterns with an intrisc version.
+// patterns with an intrinsic version.
 bool PhaseIdealLoop::do_intrinsify_fill() {
   bool changed = false;
   for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
@@ -2536,8 +2536,9 @@
   }
 
   // Make sure the address expression can be handled.  It should be
-  // head->phi * elsize + con.  head->phi might have a ConvI2L.
+  // head->phi * elsize + con.  head->phi might have a ConvI2L(CastII()).
   Node* elements[4];
+  Node* cast = NULL;
   Node* conv = NULL;
   bool found_index = false;
   int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
@@ -2552,6 +2553,12 @@
         conv = value;
         value = value->in(1);
       }
+      if (value->Opcode() == Op_CastII &&
+          value->as_CastII()->has_range_check()) {
+        // Skip range check dependent CastII nodes
+        cast = value;
+        value = value->in(1);
+      }
 #endif
       if (value != head->phi()) {
         msg = "unhandled shift in address";
@@ -2564,9 +2571,16 @@
         }
       }
     } else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
-      if (n->in(1) == head->phi()) {
+      conv = n;
+      n = n->in(1);
+      if (n->Opcode() == Op_CastII &&
+          n->as_CastII()->has_range_check()) {
+        // Skip range check dependent CastII nodes
+        cast = n;
+        n = n->in(1);
+      }
+      if (n == head->phi()) {
         found_index = true;
-        conv = n;
       } else {
         msg = "unhandled input to ConvI2L";
       }
@@ -2625,6 +2639,7 @@
   // Address elements are ok
   if (con)   ok.set(con->_idx);
   if (shift) ok.set(shift->_idx);
+  if (cast)  ok.set(cast->_idx);
   if (conv)  ok.set(conv->_idx);
 
   for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) {
--- a/src/share/vm/opto/loopopts.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/loopopts.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -772,6 +772,9 @@
 #ifdef _LP64
         if (m->Opcode() == Op_ConvI2L)
           return false;
+        if (m->is_CastII() && m->isa_CastII()->has_range_check()) {
+          return false;
+        }
 #endif
       }
     }
--- a/src/share/vm/opto/node.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/node.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -521,6 +521,11 @@
     C->add_macro_node(n);
   if (is_expensive())
     C->add_expensive_node(n);
+  // If the cloned node is a range check dependent CastII, add it to the list.
+  CastIINode* cast = n->isa_CastII();
+  if (cast != NULL && cast->has_range_check()) {
+    C->add_range_check_cast(cast);
+  }
 
   n->set_idx(C->next_unique()); // Get new unique index as well
   debug_only( n->verify_construction() );
@@ -649,6 +654,11 @@
   if (is_expensive()) {
     compile->remove_expensive_node(this);
   }
+  CastIINode* cast = isa_CastII();
+  if (cast != NULL && cast->has_range_check()) {
+    compile->remove_range_check_cast(cast);
+  }
+
   if (is_SafePoint()) {
     as_SafePoint()->delete_replaced_nodes();
   }
@@ -1344,6 +1354,10 @@
       if (dead->is_expensive()) {
         igvn->C->remove_expensive_node(dead);
       }
+      CastIINode* cast = dead->isa_CastII();
+      if (cast != NULL && cast->has_range_check()) {
+        igvn->C->remove_range_check_cast(cast);
+      }
       igvn->C->record_dead_node(dead->_idx);
       // Kill all inputs to the dead guy
       for (uint i=0; i < dead->req(); i++) {
--- a/src/share/vm/opto/node.hpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/node.hpp	Fri Feb 05 09:28:57 2016 -0800
@@ -54,6 +54,7 @@
 class CatchNode;
 class CatchProjNode;
 class CheckCastPPNode;
+class CastIINode;
 class ClearArrayNode;
 class CmpNode;
 class CodeBuffer;
@@ -603,6 +604,7 @@
     DEFINE_CLASS_ID(Type,  Node, 2)
       DEFINE_CLASS_ID(Phi,   Type, 0)
       DEFINE_CLASS_ID(ConstraintCast, Type, 1)
+        DEFINE_CLASS_ID(CastII, ConstraintCast, 0)
       DEFINE_CLASS_ID(CheckCastPP, Type, 2)
       DEFINE_CLASS_ID(CMove, Type, 3)
       DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
@@ -727,6 +729,7 @@
   DEFINE_CLASS_QUERY(Catch)
   DEFINE_CLASS_QUERY(CatchProj)
   DEFINE_CLASS_QUERY(CheckCastPP)
+  DEFINE_CLASS_QUERY(CastII)
   DEFINE_CLASS_QUERY(ConstraintCast)
   DEFINE_CLASS_QUERY(ClearArray)
   DEFINE_CLASS_QUERY(CMove)
--- a/src/share/vm/opto/parse2.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/parse2.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -154,7 +154,9 @@
   // Check for always knowing you are throwing a range-check exception
   if (stopped())  return top();
 
-  Node* ptr = array_element_address(ary, idx, type, sizetype);
+  // Make array address computation control dependent to prevent it
+  // from floating above the range check during loop optimizations.
+  Node* ptr = array_element_address(ary, idx, type, sizetype, control());
 
   if (result2 != NULL)  *result2 = elemtype;
 
@@ -457,9 +459,12 @@
 #ifdef _LP64
   // Clean the 32-bit int into a real 64-bit offset.
   // Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
-  const TypeLong* lkeytype = TypeLong::make(CONST64(0), num_cases-1, Type::WidenMin);
-  key_val       = _gvn.transform( new (C) ConvI2LNode(key_val, lkeytype) );
+  const TypeInt* ikeytype = TypeInt::make(0, num_cases-1, Type::WidenMin);
+  // Make I2L conversion control dependent to prevent it from
+  // floating above the range check during loop optimizations.
+  key_val = C->constrained_convI2L(&_gvn, key_val, ikeytype, control());
 #endif
+
   // Shift the value by wordsize so we have an index into the table, rather
   // than a switch value
   Node *shiftWord = _gvn.MakeConX(wordSize);
--- a/src/share/vm/opto/phaseX.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/phaseX.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1339,6 +1339,10 @@
       if (dead->is_expensive()) {
         C->remove_expensive_node(dead);
       }
+      CastIINode* cast = dead->isa_CastII();
+      if (cast != NULL && cast->has_range_check()) {
+        C->remove_range_check_cast(cast);
+      }
     }
   } // while (_stack.is_nonempty())
 }
--- a/src/share/vm/opto/superword.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/opto/superword.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -2388,6 +2388,11 @@
       return true;
     }
   } else if (opc == Op_ConvI2L) {
+    if (n->in(1)->Opcode() == Op_CastII &&
+        n->in(1)->as_CastII()->has_range_check()) {
+      // Skip range check dependent CastII nodes
+      n = n->in(1);
+    }
     if (scaled_iv_plus_offset(n->in(1))) {
       return true;
     }
--- a/src/share/vm/prims/jvmtiEnv.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/prims/jvmtiEnv.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -946,7 +946,7 @@
     return JVMTI_ERROR_INVALID_THREAD;
 
   Handle thread_obj(current_thread, thread_oop);
-  typeArrayHandle    name;
+  Handle name;
   ThreadPriority priority;
   Handle     thread_group;
   Handle context_class_loader;
@@ -954,7 +954,7 @@
 
   { MutexLocker mu(Threads_lock);
 
-    name = typeArrayHandle(current_thread, java_lang_Thread::name(thread_obj()));
+    name = Handle(current_thread, java_lang_Thread::name(thread_obj()));
     priority = java_lang_Thread::priority(thread_obj());
     thread_group = Handle(current_thread, java_lang_Thread::threadGroup(thread_obj()));
     is_daemon = java_lang_Thread::is_daemon(thread_obj());
@@ -965,7 +965,7 @@
   { const char *n;
 
     if (name() != NULL) {
-      n = UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length());
+      n = java_lang_String::as_utf8_string(name());
     } else {
       n = UNICODE::as_utf8(NULL, 0);
     }
--- a/src/share/vm/prims/jvmtiTrace.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/prims/jvmtiTrace.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -266,11 +266,11 @@
   if (threadObj == NULL) {
     return "NULL";
   }
-  typeArrayOop name = java_lang_Thread::name(threadObj);
+  oop name = java_lang_Thread::name(threadObj);
   if (name == NULL) {
     return "<NOT FILLED IN>";
   }
-  return UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length());
+  return java_lang_String::as_utf8_string(name);
 }
 
 
--- a/src/share/vm/runtime/thread.cpp	Mon Feb 01 16:28:45 2016 -0800
+++ b/src/share/vm/runtime/thread.cpp	Fri Feb 05 09:28:57 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -2926,13 +2926,13 @@
   const char* name_str;
   oop thread_obj = threadObj();
   if (thread_obj != NULL) {
-    typeArrayOop name = java_lang_Thread::name(thread_obj);
+    oop name = java_lang_Thread::name(thread_obj);
     if (name != NULL) {
       if (buf == NULL) {
-        name_str = UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length());
+        name_str = java_lang_String::as_utf8_string(name);
       }
       else {
-        name_str = UNICODE::as_utf8((jchar*) name->base(T_CHAR), name->length(), buf, buflen);
+        name_str = java_lang_String::as_utf8_string(name, buf, buflen);
       }
     }
     else if (is_attaching_via_jni()) { // workaround for 6412693 - see 6404306
--- a/test/compiler/loopopts/CountedLoopProblem.java	Mon Feb 01 16:28:45 2016 -0800
+++ b/test/compiler/loopopts/CountedLoopProblem.java	Fri Feb 05 09:28:57 2016 -0800
@@ -36,18 +36,22 @@
     public static void main(String[] args) throws Exception {
         Random r = new Random(42);
         int x = 0;
-        StringBuilder sb = new StringBuilder();
-        for(int i = 0; i < 1000000; ++i) {
-            int v = Math.abs(r.nextInt());
-            sb.append('+').append(v).append('\n');
-            x += v;
-            // To trigger the problem we must OSR in the following loop
-            // To make the problem 100% reproducible run with -XX:-TieredCompilation -XX:OSROnlyBCI=62
-            while(x < 0) x += 1000000000;
-            sb.append('=').append(x).append('\n');
-        }
-        if (sb.toString().hashCode() != 0xaba94591) {
-            throw new Exception("Unexpected result");
+        try {
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i < 1000000; ++i) {
+                int v = Math.abs(r.nextInt());
+                sb.append('+').append(v).append('\n');
+                x += v;
+                // To trigger the problem we must OSR in the following loop
+                // To make the problem 100% reproducible run with -XX:-TieredCompilation -XX:OSROnlyBCI=62
+                while(x < 0) x += 1000000000;
+                sb.append('=').append(x).append('\n');
+            }
+            if (sb.toString().hashCode() != 0xaba94591) {
+                throw new Exception("Unexpected result");
+            }
+        } catch(OutOfMemoryError e) {
+            // small heap, ignore
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/loopopts/TestLoopPeeling.java	Fri Feb 05 09:28:57 2016 -0800
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8078262
+ * @summary Tests correct dominator information after loop peeling.
+ * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopPeeling::test* TestLoopPeeling
+ */
+public class TestLoopPeeling {
+
+    public int[] array = new int[100];
+
+    public static void main(String args[]) {
+        TestLoopPeeling test = new TestLoopPeeling();
+        try {
+            test.testArrayAccess(0, 1);
+            test.testArrayAllocation(0, 1);
+        } catch (Exception e) {
+            // Ignore exceptions
+        }
+    }
+
+    public void testArrayAccess(int index, int inc) {
+        int storeIndex = -1;
+
+        for (; index < 10; index += inc) {
+            // This loop invariant check triggers loop peeling because it can
+            // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+            if (inc == 42) return;
+
+            // This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) )
+            // prevents the split if optimization that would otherwise clone the
+            // LShiftL and ConvI2L nodes and assign them to their corresponding array
+            // address computation (see 'PhaseIdealLoop::split_if_with_blocks_post').
+            if (storeIndex > 0 && array[storeIndex] == 42) return;
+
+            if (index == 42) {
+                // This store and the corresponding range check are moved out of the
+                // loop and both used after old loop and the peeled iteration exit.
+                // For the peeled iteration, storeIndex is always -1 and the ConvI2L
+                // is replaced by TOP. However, the range check is not folded because
+                // we don't do the split if optimization in PhaseIdealLoop2.
+                // As a result, we have a (dead) control path from the peeled iteration
+                // to the StoreI but the data path is removed.
+                array[storeIndex] = 1;
+                return;
+            }
+
+            storeIndex++;
+        }
+    }
+
+    public byte[] testArrayAllocation(int index, int inc) {
+        int allocationCount = -1;
+        byte[] result;
+
+        for (; index < 10; index += inc) {
+            // This loop invariant check triggers loop peeling because it can
+            // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+            if (inc == 42) return null;
+
+            if (index == 42) {
+                // This allocation and the corresponding size check are moved out of the
+                // loop and both used after old loop and the peeled iteration exit.
+                // For the peeled iteration, allocationCount is always -1 and the ConvI2L
+                // is replaced by TOP. However, the size check is not folded because
+                // we don't do the split if optimization in PhaseIdealLoop2.
+                // As a result, we have a (dead) control path from the peeled iteration
+                // to the allocation but the data path is removed.
+                result = new byte[allocationCount];
+                return result;
+            }
+
+            allocationCount++;
+        }
+        return null;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/stress/gc/TestStressRSetCoarsening.java	Fri Feb 05 09:28:57 2016 -0800
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.concurrent.TimeoutException;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestStressRSetCoarsening.java
+ * @key stress
+ * @bug 8146984 8147087
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 3G
+ *
+ * @summary Stress G1 Remembered Set by creating a lot of cross region links
+ * @library /testlibrary /testlibrary/whitebox
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  1  0 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx500m -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  1 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx500m -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 42 10 300
+ * @run main/othervm/timeout=300
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening  2 0 300
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 500 0  1800
+ * @run main/othervm/timeout=1800
+ *     -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ *     -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ *     -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 10  10 1800
+ */
+
+/**
+ * What the test does.
+ * Preparation stage:
+ *   Fill out ~90% of the heap with objects, each object is an object array.
+ *   If we want to allocate K objects per region, we calculate N to meet:
+ *      sizeOf(Object[N]) ~= regionSize / K
+ * Stress stage:
+ *   No more allocation, so no more GC.
+ *   We will perform a number of  iterations. On each iteration i,
+ *   for each pair of regions Rx and Ry we will set c[i] references
+ *   from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
+ *   concurrent mark cycle will be initiated (to recalculate remembered sets).
+ *   As the result RSet will be growing up and down, up and down many times.
+ *
+ * The test expects: no crash and no timeouts.
+ *
+ * Test Parameters:
+ *   args[0] - number of objects per Heap Region (1 - means humongous)
+ *   args[1] - number of regions to refresh to provoke GC at the end of cycle.
+ *             (0 - means no GC, i.e. no reading from RSet)
+ *   args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
+ */
+public class TestStressRSetCoarsening {
+
+    public static void main(String... args) throws InterruptedException {
+        if (args.length != 3) {
+            throw new IllegalArgumentException("Wrong number of arguments " + args.length);
+        }
+        int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
+        int regsToRefresh = Integer.parseInt(args[1]);  // 0 means no regions to refresh at the end of cycle
+        int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
+        new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
+    }
+
+    private static final long KB = 1024;
+    private static final long MB = 1024 * KB;
+
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    public final Object[][] storage;
+
+    /**
+     * Number of objects per region. This is a test parameter.
+     */
+    public final int K;
+
+    /**
+     * Length of object array: sizeOf(Object[N]) ~= regionSize / K
+     * N will be calculated as function of K.
+     */
+    public final int N;
+
+    /**
+     * How many regions involved into testing.
+     * Will be calculated as heapFractionToAllocate * freeRegionCount.
+     */
+    public final int regionCount;
+
+    /**
+     * How much heap to use.
+     */
+    public final float heapFractionToAllocate = 0.9f;
+
+    /**
+     * How many regions to be refreshed at the end of cycle.
+     * This is a test parameter.
+     */
+    public final int regsToRefresh;
+
+    /**
+     * Initial time.
+     */
+    public final long start;
+
+    /**
+     * Time when the test should stop working.
+     */
+    public final long finishAt;
+
+    /**
+     * Does pre-calculation and allocate necessary objects.
+     *
+     * @param objPerRegions how many objects per G1 heap region
+     */
+    TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
+        this.K = objPerRegions;
+        this.regsToRefresh = regsToRefresh;
+        this.start = System.currentTimeMillis();
+        this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
+
+        long regionSize = WB.g1RegionSize();
+
+        // How many free regions
+        Runtime rt = Runtime.getRuntime();
+        long used = rt.totalMemory() - rt.freeMemory();
+        long totalFree = rt.maxMemory() - used;
+        regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
+        long toAllocate = regionCount * regionSize;
+        System.out.println("%% Test parameters");
+        System.out.println("%%   Objects per region              : " + K);
+        System.out.println("%%   Heap fraction to allocate       : " + (int) (heapFractionToAllocate * 100) + "%");
+        System.out.println("%%   Regions to refresh to provoke GC: " + regsToRefresh);
+
+        System.out.println("%% Memory");
+        System.out.println("%%   used          :        " + used / MB + "M");
+        System.out.println("%%   available     :        " + totalFree / MB + "M");
+        System.out.println("%%   to allocate   :        " + toAllocate / MB + "M");
+        System.out.println("%%     (in regs)   :        " + regionCount);
+        System.out.println("%%   G1 Region Size:        " + regionSize / MB + "M");
+
+        int refSize = WB.getHeapOopSize();
+
+        // Calculate N:    K*sizeOf(Object[N]) ~= regionSize
+        //                 sizeOf(Object[N]) ~=  (N+4)*refSize
+        // ==>
+        //                 N = regionSize / K / refSize - 4;
+        N = (int) ((regionSize / K) / refSize) - 5;
+
+        /*
+         *   --------------
+         *   region0   storage[0]        = new Object[N]
+         *             ...
+         *             storage[K-1]      = new Object[N]
+         *   ---------------
+         *   region1   storage[K]        = new Object[N]
+         *             ...
+         *             storage[2*K - 1]  = new Object[N]
+         *   --------------
+         *   ...
+         *   --------------
+         *   regionX   storage[X*K]         = new Object[N]
+         *             ...
+         *             storage[(X+1)*K -1]  = new Object[N]
+         *    where X = HeapFraction * TotalRegions
+         *   -------------
+         */
+        System.out.println("%% Objects");
+        System.out.println("%%   N (array length)      : " + N);
+        System.out.println("%%   K (objects in regions): " + K);
+        System.out.println("%%   Reference size        : " + refSize);
+        System.out.println("%%   Approximate obj size  : " + (N + 2) * refSize / KB + "K)");
+
+        storage = new Object[regionCount * K][];
+        for (int i = 0; i < storage.length; i++) {
+            storage[i] = new Object[N];
+        }
+    }
+
+    public void go() throws InterruptedException {
+        // threshold for sparce -> fine
+        final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
+
+        // threshold for fine -> coarse
+        final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
+
+        // regToRegRefCounts - array of reference counts from region to region
+        // at the the end of iteration.
+        // The number of test iterations is array length - 1.
+        // If c[i] > c[i-1] then during the iteration i more references will
+        // be created.
+        // If c[i] < c[i-1] then some referenes will be cleaned.
+        int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
+            COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
+
+        // For progress tracking
+        int[] progress = new int[regToRegRefCounts.length];
+        progress[0] = 0;
+        for (int i = 1; i < regToRegRefCounts.length; i++) {
+            progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
+        }
+        try {
+            for (int i = 1; i < regToRegRefCounts.length; i++) {
+                int pre = regToRegRefCounts[i - 1];
+                int cur = regToRegRefCounts[i];
+                float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
+
+                System.out.println("%% step " + i
+                        + " out of " + (regToRegRefCounts.length - 1)
+                        + " (~" + (int) (100 * prog) + "% done)");
+                System.out.println("%%      " + pre + "  --> " + cur);
+                for (int to = 0; to < regionCount; to++) {
+                    // Select a celebrity object that we will install references to.
+                    // The celebrity will be referred from all other regions.
+                    // If the number of references after should be less than they
+                    // were before, select NULL.
+                    Object celebrity = cur > pre ? storage[to * K] : null;
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+
+                        int step = cur > pre ? +1 : -1;
+                        for (int rn = pre; rn != cur; rn += step) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
+                            if (System.currentTimeMillis() > finishAt) {
+                                throw new TimeoutException();
+                            }
+                        }
+                    }
+                }
+                if (pre > cur) {
+                    // Number of references went down.
+                    // Need to provoke recalculation of RSet.
+                    WB.g1StartConcMarkCycle();
+                    while (WB.g1InConcurrentMark()) {
+                        Thread.sleep(1);
+                    }
+                }
+
+                // To force the use of rememebered set entries we need to provoke a GC.
+                // To induce some fragmentation, and some mixed GCs, we need
+                // to make a few objects unreachable.
+                for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
+                    int to = toClean % regionCount;
+                    // Need to remove all references from all regions to the region 'to'
+                    for (int from = 0; from < regionCount; from++) {
+                        if (to == from) {
+                            continue; // no need to refer to itself
+                        }
+                        for (int rn = 0; rn <= cur; rn++) {
+                            storage[getY(to, from, rn)][getX(to, from, rn)] = null;
+                        }
+                    }
+                    // 'Refresh' storage elements for the region 'to'
+                    // After that loop all 'old' objects in the region 'to'
+                    // should become unreachable.
+                    for (int k = 0; k < K; k++) {
+                        storage[(to * K + k) % storage.length] = new Object[N];
+                    }
+                }
+            }
+        } catch (TimeoutException e) {
+            System.out.println("%% TIMEOUT!!!");
+        }
+        long now = System.currentTimeMillis();
+        System.out.println("%% Summary");
+        System.out.println("%%   Time spent          : " + ((now - start) / 1000) + " seconds");
+        System.out.println("%%   Free memory left    : " + Runtime.getRuntime().freeMemory() / KB + "K");
+        System.out.println("%% Test passed");
+    }
+
+    /**
+     * Returns X index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return X index in the range: [0 ... N-1]
+     */
+    private int getX(int to, int from, int rn) {
+        return (rn * regionCount + to) % N;
+    }
+
+    /**
+     * Returns Y index in the Storage of the reference #rn from the region
+     * 'from' to the region 'to'.
+     *
+     * @param to region # to refer to
+     * @param from region # to refer from
+     * @param rn number of reference
+     *
+     * @return Y index in the range: [0 ... K*regionCount -1]
+     */
+    private int getY(int to, int from, int rn) {
+        return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
+    }
+}
+