changeset 23865:d14e327c9b6a

Merge
author asaha
date Thu, 18 Feb 2016 09:49:33 -0800
parents 4cd449d96635 (current diff) 5ed7f17c7804 (diff)
children 20dbd8a8e6b7 81f376fd8bd4
files .hgtags
diffstat 13 files changed, 686 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Feb 04 15:13:49 2016 -0800
+++ b/.hgtags	Thu Feb 18 09:49:33 2016 -0800
@@ -817,6 +817,8 @@
 32b682649973231b54740c09b10889660f6ebde5 jdk8u75-b04
 1f43bd4fab06d2ca5d1964611df14d8506d6b36e jdk8u75-b05
 916712f178c39d0acbc590f38802133fc86a7346 jdk8u75-b06
+8c791dd1c24d85ebd18b03d49185c2a25263c129 jdk8u75-b07
+e4a935cb6f7178912fd653e2a9514eadec7935ab jdk8u75-b08
 d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00
 c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01
 218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02
@@ -824,3 +826,5 @@
 16f7b676725aadafb79ea105b22df112e2593a78 jdk8u76-b04
 35bfaf7f9021b5c1e86effbeac075753a82e9a0c jdk8u76-b05
 6449ee3bf707225372709ac830524c00984c601f jdk8u76-b06
+7d1074c74d6000ec8257917ebfcee3fed4249f7d jdk8u76-b07
+392f8722fc513e28f78c5c563d51af7dc8466b29 jdk8u76-b08
--- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java	Thu Feb 04 15:13:49 2016 -0800
+++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java	Thu Feb 18 09:49:33 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -253,29 +253,30 @@
   public static final int _fast_sgetfield       = 210;
   public static final int _fast_aputfield       = 211;
   public static final int _fast_bputfield       = 212;
-  public static final int _fast_cputfield       = 213;
-  public static final int _fast_dputfield       = 214;
-  public static final int _fast_fputfield       = 215;
-  public static final int _fast_iputfield       = 216;
-  public static final int _fast_lputfield       = 217;
-  public static final int _fast_sputfield       = 218;
-  public static final int _fast_aload_0         = 219;
-  public static final int _fast_iaccess_0       = 220;
-  public static final int _fast_aaccess_0       = 221;
-  public static final int _fast_faccess_0       = 222;
-  public static final int _fast_iload           = 223;
-  public static final int _fast_iload2          = 224;
-  public static final int _fast_icaload         = 225;
-  public static final int _fast_invokevfinal    = 226;
-  public static final int _fast_linearswitch    = 227;
-  public static final int _fast_binaryswitch    = 228;
-  public static final int _fast_aldc            = 229;
-  public static final int _fast_aldc_w          = 230;
-  public static final int _return_register_finalizer = 231;
-  public static final int _invokehandle         = 232;
-  public static final int _shouldnotreachhere   = 233; // For debugging
+  public static final int _fast_zputfield       = 213;
+  public static final int _fast_cputfield       = 214;
+  public static final int _fast_dputfield       = 215;
+  public static final int _fast_fputfield       = 216;
+  public static final int _fast_iputfield       = 217;
+  public static final int _fast_lputfield       = 218;
+  public static final int _fast_sputfield       = 219;
+  public static final int _fast_aload_0         = 220;
+  public static final int _fast_iaccess_0       = 221;
+  public static final int _fast_aaccess_0       = 222;
+  public static final int _fast_faccess_0       = 223;
+  public static final int _fast_iload           = 224;
+  public static final int _fast_iload2          = 225;
+  public static final int _fast_icaload         = 226;
+  public static final int _fast_invokevfinal    = 227;
+  public static final int _fast_linearswitch    = 228;
+  public static final int _fast_binaryswitch    = 229;
+  public static final int _fast_aldc            = 230;
+  public static final int _fast_aldc_w          = 231;
+  public static final int _return_register_finalizer = 232;
+  public static final int _invokehandle         = 233;
+  public static final int _shouldnotreachhere   = 234; // For debugging
 
-  public static final int number_of_codes       = 234;
+  public static final int number_of_codes       = 235;
 
   // Flag bits derived from format strings, can_trap, can_rewrite, etc.:
   // semantic flags:
@@ -776,6 +777,7 @@
 
     def(_fast_aputfield      , "fast_aputfield"      , "bJJ"  , null    , BasicType.getTObject() ,  0, true , _putfield       );
     def(_fast_bputfield      , "fast_bputfield"      , "bJJ"  , null    , BasicType.getTInt()    ,  0, true , _putfield       );
+    def(_fast_zputfield      , "fast_zputfield"      , "bJJ"  , null    , BasicType.getTInt()    ,  0, true , _putfield       );
     def(_fast_cputfield      , "fast_cputfield"      , "bJJ"  , null    , BasicType.getTChar()   ,  0, true , _putfield       );
     def(_fast_dputfield      , "fast_dputfield"      , "bJJ"  , null    , BasicType.getTDouble() ,  0, true , _putfield       );
     def(_fast_fputfield      , "fast_fputfield"      , "bJJ"  , null    , BasicType.getTFloat()  ,  0, true , _putfield       );
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/cpu/ppc/vm/interp_masm_ppc_64.cpp	Thu Feb 18 09:49:33 2016 -0800
@@ -174,6 +174,7 @@
     case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
                break;
     case btos: // fall through
+    case ztos: // fall through
     case ctos: // fall through
     case stos: // fall through
     case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
@@ -302,6 +303,7 @@
   switch (state) {
     case atos: push_ptr();                break;
     case btos:
+    case ztos:
     case ctos:
     case stos:
     case itos: push_i();                  break;
@@ -317,6 +319,7 @@
   switch (state) {
     case atos: pop_ptr();            break;
     case btos:
+    case ztos:
     case ctos:
     case stos:
     case itos: pop_i();              break;
@@ -751,6 +754,43 @@
   stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP
 }
 
+void InterpreterMacroAssembler::narrow(Register result) {
+  Register ret_type = R11_scratch1;
+  ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
+  lbz(ret_type, in_bytes(ConstMethod::result_type_offset()), R11_scratch1);
+
+  Label notBool, notByte, notChar, done;
+
+  // common case first
+  cmpwi(CCR0, ret_type, T_INT);
+  beq(CCR0, done);
+
+  cmpwi(CCR0, ret_type, T_BOOLEAN);
+  bne(CCR0, notBool);
+  andi(result, result, 0x1);
+  b(done);
+
+  bind(notBool);
+  cmpwi(CCR0, ret_type, T_BYTE);
+  bne(CCR0, notByte);
+  extsb(result, result);
+  b(done);
+
+  bind(notByte);
+  cmpwi(CCR0, ret_type, T_CHAR);
+  bne(CCR0, notChar);
+  andi(result, result, 0xffff);
+  b(done);
+
+  bind(notChar);
+  // cmpwi(CCR0, ret_type, T_SHORT);  // all that's left
+  // bne(CCR0, done);
+  extsh(result, result);
+
+  // Nothing to do for T_INT
+  bind(done);
+}
+
 // Remove activation.
 //
 // Unlock the receiver if this is a synchronized method.
--- a/src/cpu/ppc/vm/interp_masm_ppc_64.hpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/cpu/ppc/vm/interp_masm_ppc_64.hpp	Thu Feb 18 09:49:33 2016 -0800
@@ -149,6 +149,8 @@
   void get_cpool_and_tags(Register Rcpool, Register Rtags);
   void is_a(Label& L);
 
+  void narrow(Register result);
+
   // Java Call Helpers
   void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2);
 
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/cpu/ppc/vm/interpreter_ppc.cpp	Thu Feb 18 09:49:33 2016 -0800
@@ -640,6 +640,16 @@
     __ blr();
   }
 
+  if (branch_table[ztos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[ztos] = __ pc(); // non-volatile_entry point
+    __ lbzx(R3_RET, Rclass_or_obj, Roffset);
+    __ extsb(R3_RET, R3_RET);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
   if (branch_table[ctos] == 0) { // generate only once
     __ align(32, 28, 28); // align load
     __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
--- a/src/cpu/ppc/vm/templateInterpreter_ppc.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/cpu/ppc/vm/templateInterpreter_ppc.cpp	Thu Feb 18 09:49:33 2016 -0800
@@ -154,6 +154,7 @@
   switch (state) {
     case ltos:
     case btos:
+    case ztos:
     case ctos:
     case stos:
     case atos:
@@ -200,6 +201,7 @@
   switch (state) {
     case ltos:
     case btos:
+    case ztos:
     case ctos:
     case stos:
     case atos:
@@ -1642,12 +1644,14 @@
   // Copied from TemplateTable::_return.
   // Restoration of lr done by remove_activation.
   switch (state) {
+    // Narrow result if state is itos but result type is smaller.
+    case itos: __ narrow(R17_tos); /* fall through */
     case ltos:
     case btos:
+    case ztos:
     case ctos:
     case stos:
-    case atos:
-    case itos: __ mr(R3_RET, R17_tos); break;
+    case atos: __ mr(R3_RET, R17_tos); break;
     case ftos:
     case dtos: __ fmr(F1_RET, F15_ftos); break;
     case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
@@ -1717,6 +1721,10 @@
     bname = "trace_code_btos {";
     tsize = 2;
     break;
+  case ztos:
+    bname = "trace_code_ztos {";
+    tsize = 2;
+    break;
   case ctos:
     bname = "trace_code_ctos {";
     tsize = 2;
--- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp	Thu Feb 18 09:49:33 2016 -0800
@@ -173,6 +173,7 @@
   switch (new_bc) {
     case Bytecodes::_fast_aputfield:
     case Bytecodes::_fast_bputfield:
+    case Bytecodes::_fast_zputfield:
     case Bytecodes::_fast_cputfield:
     case Bytecodes::_fast_dputfield:
     case Bytecodes::_fast_fputfield:
@@ -969,9 +970,21 @@
                  Rarray   = R12_scratch2,
                  Rscratch = R3_ARG1;
   __ pop_i(Rindex);
+  __ pop_ptr(Rarray);
   // tos: val
-  // Rarray: array ptr (popped by index_check)
-  __ index_check(Rarray, Rindex, 0, Rscratch, Rarray);
+
+  // Need to check whether array is boolean or byte
+  // since both types share the bastore bytecode.
+  __ load_klass(Rscratch, Rarray);
+  __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch);
+  int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit());
+  __ testbitdi(CCR0, R0, Rscratch, diffbit);
+  Label L_skip;
+  __ bfalse(CCR0, L_skip);
+  __ andi(R17_tos, R17_tos, 1);  // if it is a T_BOOLEAN array, mask the stored value to 0/1
+  __ bind(L_skip);
+
+  __ index_check_without_pop(Rarray, Rindex, 0, Rscratch, Rarray);
   __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray);
 }
 
@@ -2100,12 +2113,16 @@
   __ remove_activation(state, /* throw_monitor_exception */ true);
   // Restoration of lr done by remove_activation.
   switch (state) {
+    // Narrow result if state is itos but result type is smaller.
+    // Need to narrow in the return bytecode rather than in generate_return_entry
+    // since compiled code callers expect the result to already be narrowed.
+    case itos: __ narrow(R17_tos); /* fall through */
     case ltos:
     case btos:
+    case ztos:
     case ctos:
     case stos:
-    case atos:
-    case itos: __ mr(R3_RET, R17_tos); break;
+    case atos: __ mr(R3_RET, R17_tos); break;
     case ftos:
     case dtos: __ fmr(F1_RET, F15_ftos); break;
     case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
@@ -2501,6 +2518,21 @@
   __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
 
   __ align(32, 28, 28); // Align load.
+  // __ bind(Lztos); (same code as btos)
+  __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+  assert(branch_table[ztos] == 0, "can't compute twice");
+  branch_table[ztos] = __ pc(); // non-volatile_entry point
+  __ lbzx(R17_tos, Rclass_or_obj, Roffset);
+  __ extsb(R17_tos, R17_tos);
+  __ push(ztos);
+  if (!is_static) {
+    // use btos rewriting, no truncating to t/f bit is needed for getfield.
+    patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch);
+  }
+  __ beq(CCR6, Lacquire); // Volatile?
+  __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+  __ align(32, 28, 28); // Align load.
   // __ bind(Lctos);
   __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
   assert(branch_table[ctos] == 0, "can't compute twice");
@@ -2590,6 +2622,7 @@
         case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break;
         case Bytecodes::_fast_iputfield: // Fall through
         case Bytecodes::_fast_bputfield: // Fall through
+        case Bytecodes::_fast_zputfield: // Fall through
         case Bytecodes::_fast_cputfield: // Fall through
         case Bytecodes::_fast_sputfield: __ push_i(); offs+=  Interpreter::stackElementSize; break;
         case Bytecodes::_fast_lputfield: __ push_l(); offs+=2*Interpreter::stackElementSize; break;
@@ -2630,6 +2663,7 @@
       case Bytecodes::_fast_aputfield: __ pop_ptr(); break;
       case Bytecodes::_fast_iputfield: // Fall through
       case Bytecodes::_fast_bputfield: // Fall through
+      case Bytecodes::_fast_zputfield: // Fall through
       case Bytecodes::_fast_cputfield: // Fall through
       case Bytecodes::_fast_sputfield: __ pop_i(); break;
       case Bytecodes::_fast_lputfield: __ pop_l(); break;
@@ -2781,6 +2815,21 @@
   __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
 
   __ align(32, 28, 28); // Align pop.
+  // __ bind(Lztos);
+  __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+  assert(branch_table[ztos] == 0, "can't compute twice");
+  branch_table[ztos] = __ pc(); // non-volatile_entry point
+  __ pop(ztos);
+  if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+  __ andi(R17_tos, R17_tos, 0x1);
+  __ stbx(R17_tos, Rclass_or_obj, Roffset);
+  if (!is_static) { patch_bytecode(Bytecodes::_fast_zputfield, Rbc, Rscratch, true, byte_no); }
+  if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+    __ beq(CR_is_vol, Lvolatile); // Volatile?
+  }
+  __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+  __ align(32, 28, 28); // Align pop.
   // __ bind(Lctos);
   __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
   assert(branch_table[ctos] == 0, "can't compute twice");
@@ -2895,6 +2944,9 @@
       __ stdx(R17_tos, Rclass_or_obj, Roffset);
       break;
 
+    case Bytecodes::_fast_zputfield:
+      __ andi(R17_tos, R17_tos, 0x1);  // boolean is true if LSB is 1
+      // fall through to bputfield
     case Bytecodes::_fast_bputfield:
       __ stbx(R17_tos, Rclass_or_obj, Roffset);
       break;
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu Feb 18 09:49:33 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	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp	Thu Feb 18 09:49:33 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	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp	Thu Feb 18 09:49:33 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/prims/jni.cpp	Thu Feb 04 15:13:49 2016 -0800
+++ b/src/share/vm/prims/jni.cpp	Thu Feb 18 09:49:33 2016 -0800
@@ -1121,7 +1121,14 @@
  protected:
   va_list _ap;
 
-  inline void get_bool()   { _arguments->push_int(va_arg(_ap, jint)); } // bool is coerced to int when using va_arg
+  inline void get_bool()   {
+    // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and
+    // 0 to JNI_FALSE.  Boolean return values from native are normalized the same in
+    // TemplateInterpreterGenerator::generate_result_handler_for and
+    // SharedRuntime::generate_native_wrapper.
+    jboolean b = va_arg(_ap, jint);
+    _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE));
+  }
   inline void get_char()   { _arguments->push_int(va_arg(_ap, jint)); } // char is coerced to int when using va_arg
   inline void get_short()  { _arguments->push_int(va_arg(_ap, jint)); } // short is coerced to int when using va_arg
   inline void get_byte()   { _arguments->push_int(va_arg(_ap, jint)); } // byte is coerced to int when using va_arg
@@ -1167,9 +1174,17 @@
       while ( 1 ) {
         switch ( fingerprint & parameter_feature_mask ) {
           case bool_parm:
+            get_bool();
+            break;
           case char_parm:
+            get_char();
+            break;
           case short_parm:
+            get_short();
+            break;
           case byte_parm:
+            get_byte();
+            break;
           case int_parm:
             get_int();
             break;
@@ -1203,7 +1218,14 @@
  protected:
   const jvalue *_ap;
 
-  inline void get_bool()   { _arguments->push_int((jint)(_ap++)->z); }
+  inline void get_bool()   {
+    // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and
+    // 0 to JNI_FALSE.  Boolean return values from native are normalized the same in
+    // TemplateInterpreterGenerator::generate_result_handler_for and
+    // SharedRuntime::generate_native_wrapper.
+    jboolean b = (_ap++)->z;
+    _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE));
+  }
   inline void get_char()   { _arguments->push_int((jint)(_ap++)->c); }
   inline void get_short()  { _arguments->push_int((jint)(_ap++)->s); }
   inline void get_byte()   { _arguments->push_int((jint)(_ap++)->b); }
--- a/test/compiler/loopopts/CountedLoopProblem.java	Thu Feb 04 15:13:49 2016 -0800
+++ b/test/compiler/loopopts/CountedLoopProblem.java	Thu Feb 18 09:49:33 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/stress/gc/TestStressRSetCoarsening.java	Thu Feb 18 09:49:33 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);
+    }
+}
+