changeset 7506:85b261e8433e

Merge
author drchase
date Thu, 04 Dec 2014 17:53:36 +0000
parents d7ae2b300af9 927664223435
children 8866247570e8
files
diffstat 24 files changed, 889 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/ci/ciTypeFlow.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/ci/ciTypeFlow.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -36,6 +36,7 @@
 #include "interpreter/bytecodes.hpp"
 #include "memory/allocation.inline.hpp"
 #include "opto/compile.hpp"
+#include "opto/node.hpp"
 #include "runtime/deoptimization.hpp"
 #include "utilities/growableArray.hpp"
 
--- a/src/share/vm/oops/method.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/oops/method.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -936,7 +936,7 @@
   // so making them eagerly shouldn't be too expensive.
   AdapterHandlerEntry* adapter = AdapterHandlerLibrary::get_adapter(mh);
   if (adapter == NULL ) {
-    THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "out of space in CodeCache for adapters");
+    THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "Out of space in CodeCache for adapters");
   }
 
   mh->set_adapter_entry(adapter);
--- a/src/share/vm/opto/escape.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/opto/escape.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -1115,6 +1115,9 @@
           // Each 4 iterations calculate how much time it will take
           // to complete graph construction.
           time.stop();
+          // Poll for requests from shutdown mechanism to quiesce compiler
+          // because Connection graph construction may take long time.
+          CompileBroker::maybe_block();
           double stop_time = time.seconds();
           double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE;
           double time_until_end = time_per_iter * (double)(java_objects_length - next);
--- a/src/share/vm/opto/graphKit.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/opto/graphKit.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -2809,7 +2809,8 @@
  */
 Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
                                         ciKlass* type,
-                                        bool not_null) {
+                                        bool not_null,
+                                        SafePointNode* sfpt) {
   // type == NULL if profiling tells us this object is always null
   if (type != NULL) {
     Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
@@ -2831,7 +2832,13 @@
       ciKlass* exact_kls = type;
       Node* slow_ctl  = type_check_receiver(exact_obj, exact_kls, 1.0,
                                             &exact_obj);
-      {
+      if (sfpt != NULL) {
+        GraphKit kit(sfpt->jvms());
+        PreserveJVMState pjvms(&kit);
+        kit.set_control(slow_ctl);
+        kit.uncommon_trap(class_reason,
+                          Deoptimization::Action_maybe_recompile);
+      } else {
         PreserveJVMState pjvms(this);
         set_control(slow_ctl);
         uncommon_trap(class_reason,
--- a/src/share/vm/opto/graphKit.hpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/opto/graphKit.hpp	Thu Dec 04 17:53:36 2014 +0000
@@ -418,7 +418,8 @@
   // Cast obj to type and emit guard unless we had too many traps here already
   Node* maybe_cast_profiled_obj(Node* obj,
                                 ciKlass* type,
-                                bool not_null = false);
+                                bool not_null = false,
+                                SafePointNode* sfpt = NULL);
 
   // Cast obj to not-null on this path
   Node* cast_not_null(Node* obj, bool do_replace_in_map = true);
--- a/src/share/vm/opto/library_call.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/opto/library_call.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -4697,10 +4697,6 @@
   Node* dest_offset = argument(3);  // type: int
   Node* length      = argument(4);  // type: int
 
-  // Check for allocation before we add nodes that would confuse
-  // tightly_coupled_allocation()
-  AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL);
-
   // The following tests must be performed
   // (1) src and dest are arrays.
   // (2) src and dest arrays must have elements of the same BasicType
@@ -4717,6 +4713,36 @@
   src  = null_check(src,  T_ARRAY);
   dest = null_check(dest, T_ARRAY);
 
+  // Check for allocation before we add nodes that would confuse
+  // tightly_coupled_allocation()
+  AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL);
+
+  SafePointNode* sfpt = NULL;
+  if (alloc != NULL) {
+    // The JVM state for uncommon traps between the allocation and
+    // arraycopy is set to the state before the allocation: if the
+    // initialization is performed by the array copy, we don't want to
+    // go back to the interpreter with an unitialized array.
+    JVMState* old_jvms = alloc->jvms();
+    JVMState* jvms = old_jvms->clone_shallow(C);
+    uint size = alloc->req();
+    sfpt = new SafePointNode(size, jvms);
+    jvms->set_map(sfpt);
+    for (uint i = 0; i < size; i++) {
+      sfpt->init_req(i, alloc->in(i));
+    }
+    // re-push array length for deoptimization
+    sfpt->ins_req(jvms->stkoff() + jvms->sp(), alloc->in(AllocateNode::ALength));
+    jvms->set_sp(jvms->sp()+1);
+    jvms->set_monoff(jvms->monoff()+1);
+    jvms->set_scloff(jvms->scloff()+1);
+    jvms->set_endoff(jvms->endoff()+1);
+    jvms->set_should_reexecute(true);
+
+    sfpt->set_i_o(map()->i_o());
+    sfpt->set_memory(map()->memory());
+  }
+
   bool notest = false;
 
   const Type* src_type  = _gvn.type(src);
@@ -4762,14 +4788,14 @@
     if (could_have_src && could_have_dest) {
       // This is going to pay off so emit the required guards
       if (!has_src) {
-        src = maybe_cast_profiled_obj(src, src_k);
+        src = maybe_cast_profiled_obj(src, src_k, true, sfpt);
         src_type  = _gvn.type(src);
         top_src  = src_type->isa_aryptr();
         has_src = (top_src != NULL && top_src->klass() != NULL);
         src_spec = true;
       }
       if (!has_dest) {
-        dest = maybe_cast_profiled_obj(dest, dest_k);
+        dest = maybe_cast_profiled_obj(dest, dest_k, true);
         dest_type  = _gvn.type(dest);
         top_dest  = dest_type->isa_aryptr();
         has_dest = (top_dest != NULL && top_dest->klass() != NULL);
@@ -4810,10 +4836,10 @@
       if (could_have_src && could_have_dest) {
         // If we can have both exact types, emit the missing guards
         if (could_have_src && !src_spec) {
-          src = maybe_cast_profiled_obj(src, src_k);
+          src = maybe_cast_profiled_obj(src, src_k, true, sfpt);
         }
         if (could_have_dest && !dest_spec) {
-          dest = maybe_cast_profiled_obj(dest, dest_k);
+          dest = maybe_cast_profiled_obj(dest, dest_k, true);
         }
       }
     }
@@ -4855,13 +4881,28 @@
     Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass);
 
     if (not_subtype_ctrl != top()) {
-      PreserveJVMState pjvms(this);
-      set_control(not_subtype_ctrl);
-      uncommon_trap(Deoptimization::Reason_intrinsic,
-                    Deoptimization::Action_make_not_entrant);
-      assert(stopped(), "Should be stopped");
+      if (sfpt != NULL) {
+        GraphKit kit(sfpt->jvms());
+        PreserveJVMState pjvms(&kit);
+        kit.set_control(not_subtype_ctrl);
+        kit.uncommon_trap(Deoptimization::Reason_intrinsic,
+                          Deoptimization::Action_make_not_entrant);
+        assert(kit.stopped(), "Should be stopped");
+      } else {
+        PreserveJVMState pjvms(this);
+        set_control(not_subtype_ctrl);
+        uncommon_trap(Deoptimization::Reason_intrinsic,
+                      Deoptimization::Action_make_not_entrant);
+        assert(stopped(), "Should be stopped");
+      }
     }
-    {
+    if (sfpt != NULL) {
+      GraphKit kit(sfpt->jvms());
+      kit.set_control(_gvn.transform(slow_region));
+      kit.uncommon_trap(Deoptimization::Reason_intrinsic,
+                        Deoptimization::Action_make_not_entrant);
+      assert(kit.stopped(), "Should be stopped");
+    } else {
       PreserveJVMState pjvms(this);
       set_control(_gvn.transform(slow_region));
       uncommon_trap(Deoptimization::Reason_intrinsic,
--- a/src/share/vm/opto/phaseX.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/opto/phaseX.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -1431,7 +1431,7 @@
             Node* castii = in1->raw_out(i);
             if (castii->in(0) != NULL && castii->in(0)->in(0) != NULL && castii->in(0)->in(0)->is_If()) {
               Node* ifnode = castii->in(0)->in(0);
-              if (ifnode->in(1) != NULL && ifnode->in(1)->in(1) == use) {
+              if (ifnode->in(1) != NULL && ifnode->in(1)->is_Bool() && ifnode->in(1)->in(1) == use) {
                 // Reprocess a CastII node that may depend on an
                 // opaque node value when the opaque node is
                 // removed. In case it carries a dependency we can do
--- a/src/share/vm/prims/whitebox.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/prims/whitebox.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -41,6 +41,7 @@
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/os.hpp"
 #include "runtime/sweeper.hpp"
+#include "runtime/javaCalls.hpp"
 #include "runtime/thread.hpp"
 #include "runtime/vm_version.hpp"
 #include "utilities/array.hpp"
@@ -771,8 +772,8 @@
   mo.notify_all();
 WB_END
 
-void WhiteBox::force_sweep() {
-  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+void WhiteBox::sweeper_thread_entry(JavaThread* thread, TRAPS) {
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     NMethodSweeper::_should_sweep = true;
@@ -780,8 +781,37 @@
   NMethodSweeper::possibly_sweep();
 }
 
-WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
-  WhiteBox::force_sweep();
+JavaThread* WhiteBox::create_sweeper_thread(TRAPS) {
+  // create sweeper thread w/ custom entry -- one iteration instead of loop
+  CodeCacheSweeperThread* sweeper_thread = new CodeCacheSweeperThread();
+  sweeper_thread->set_entry_point(&WhiteBox::sweeper_thread_entry);
+
+  // create j.l.Thread object and associate it w/ sweeper thread
+  {
+    // inherit deamon property from current thread
+    bool is_daemon = java_lang_Thread::is_daemon(JavaThread::current()->threadObj());
+
+    HandleMark hm(THREAD);
+    Handle thread_group(THREAD, Universe::system_thread_group());
+    const char* name = "WB Sweeper thread";
+    sweeper_thread->allocate_threadObj(thread_group, name, is_daemon, THREAD);
+  }
+
+  {
+    MutexLocker mu(Threads_lock, THREAD);
+    Threads::add(sweeper_thread);
+  }
+  return sweeper_thread;
+}
+
+WB_ENTRY(jobject, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
+  JavaThread* sweeper_thread = WhiteBox::create_sweeper_thread(Thread::current());
+  if (sweeper_thread == NULL) {
+    return NULL;
+  }
+  jobject result = JNIHandles::make_local(env, sweeper_thread->threadObj());
+  Thread::start(sweeper_thread);
+  return result;
 WB_END
 
 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
@@ -831,12 +861,12 @@
 WB_END
 
 int WhiteBox::get_blob_type(const CodeBlob* code) {
-  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
   return CodeCache::get_code_heap(code)->code_blob_type();
 }
 
 CodeHeap* WhiteBox::get_code_heap(int blob_type) {
-  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
   return CodeCache::get_code_heap(blob_type);
 }
 
@@ -912,7 +942,7 @@
 WB_END
 
 CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
-  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
   BufferBlob* blob;
   int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob));
   if (full_size < size) {
@@ -921,10 +951,10 @@
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type);
+    ::new (blob) BufferBlob("WB::DummyBlob", full_size);
   }
   // Track memory usage statistic after releasing CodeCache_lock
   MemoryService::track_code_cache_memory_usage();
-  ::new (blob) BufferBlob("WB::DummyBlob", full_size);
   return blob;
 }
 
@@ -1235,7 +1265,7 @@
   {CC"getCPUFeatures",     CC"()Ljava/lang/String;",  (void*)&WB_GetCPUFeatures     },
   {CC"getNMethod",         CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;",
                                                       (void*)&WB_GetNMethod         },
-  {CC"forceNMethodSweep",  CC"()V",                   (void*)&WB_ForceNMethodSweep  },
+  {CC"forceNMethodSweep0", CC"()Ljava/lang/Thread;",  (void*)&WB_ForceNMethodSweep  },
   {CC"allocateCodeBlob",   CC"(II)J",                 (void*)&WB_AllocateCodeBlob   },
   {CC"freeCodeBlob",       CC"(J)V",                  (void*)&WB_FreeCodeBlob       },
   {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries },
--- a/src/share/vm/prims/whitebox.hpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/prims/whitebox.hpp	Thu Dec 04 17:53:36 2014 +0000
@@ -27,6 +27,7 @@
 
 #include "prims/jni.h"
 
+#include "utilities/exceptions.hpp"
 #include "memory/allocation.hpp"
 #include "oops/oopsHierarchy.hpp"
 #include "oops/symbol.hpp"
@@ -56,6 +57,7 @@
 
 class CodeBlob;
 class CodeHeap;
+class JavaThread;
 
 class WhiteBox : public AllStatic {
  private:
@@ -68,7 +70,8 @@
     Symbol* signature_symbol);
   static const char* lookup_jstring(const char* field_name, oop object);
   static bool lookup_bool(const char* field_name, oop object);
-  static void force_sweep();
+  static void sweeper_thread_entry(JavaThread* thread, TRAPS);
+  static JavaThread* create_sweeper_thread(TRAPS);
   static int get_blob_type(const CodeBlob* code);
   static CodeHeap* get_code_heap(int blob_type);
   static CodeBlob* allocate_code_blob(int blob_type, int size);
--- a/src/share/vm/runtime/sweeper.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/runtime/sweeper.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -142,9 +142,6 @@
 long     NMethodSweeper::_time_counter                 = 0;    // Virtual time used to periodically invoke sweeper
 long     NMethodSweeper::_last_sweep                   = 0;    // Value of _time_counter when the last sweep happened
 int      NMethodSweeper::_seen                         = 0;    // Nof. nmethod we have currently processed in current pass of CodeCache
-int      NMethodSweeper::_flushed_count                = 0;    // Nof. nmethods flushed in current sweep
-int      NMethodSweeper::_zombified_count              = 0;    // Nof. nmethods made zombie in current sweep
-int      NMethodSweeper::_marked_for_reclamation_count = 0;    // Nof. nmethods marked for reclaim in current sweep
 
 volatile bool NMethodSweeper::_should_sweep            = true; // Indicates if we should invoke the sweeper
 volatile int  NMethodSweeper::_bytes_changed           = 0;    // Counts the total nmethod size if the nmethod changed from:
@@ -161,6 +158,7 @@
 Tickspan NMethodSweeper::_peak_sweep_time;                     // Peak time for a full sweep
 Tickspan NMethodSweeper::_peak_sweep_fraction_time;            // Peak time sweeping one fraction
 
+Monitor* NMethodSweeper::_stat_lock = new Monitor(Mutex::special, "Sweeper::Statistics", true);
 
 class MarkActivationClosure: public CodeBlobClosure {
 public:
@@ -370,9 +368,10 @@
   ResourceMark rm;
   Ticks sweep_start_counter = Ticks::now();
 
-  _flushed_count                = 0;
-  _zombified_count              = 0;
-  _marked_for_reclamation_count = 0;
+  int flushed_count                = 0;
+  int zombified_count              = 0;
+  int marked_for_reclamation_count = 0;
+  int flushed_c2_count     = 0;
 
   if (PrintMethodFlushing && Verbose) {
     tty->print_cr("### Sweep at %d out of %d", _seen, CodeCache::nof_nmethods());
@@ -386,10 +385,8 @@
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 
-    // The last invocation iterates until there are no more nmethods
     while (!_current.end()) {
       swept_count++;
-      handle_safepoint_request();
       // Since we will give up the CodeCache_lock, always skip ahead
       // to the next nmethod.  Other blobs can be deleted by other
       // threads but nmethods are only reclaimed by the sweeper.
@@ -399,9 +396,32 @@
       // Now ready to process nmethod and give up CodeCache_lock
       {
         MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
-        freed_memory += process_nmethod(nm);
+        int size = nm->total_size();
+        bool is_c2_method = nm->is_compiled_by_c2();
+
+        MethodStateChange type = process_nmethod(nm);
+        switch (type) {
+          case Flushed:
+            freed_memory += size;
+            ++flushed_count;
+            if (is_c2_method) {
+              ++flushed_c2_count;
+            }
+            break;
+          case MarkedForReclamation:
+            ++marked_for_reclamation_count;
+            break;
+          case MadeZombie:
+            ++zombified_count;
+            break;
+          case None:
+            break;
+          default:
+           ShouldNotReachHere();
+        }
       }
       _seen++;
+      handle_safepoint_request();
     }
   }
 
@@ -409,21 +429,25 @@
 
   const Ticks sweep_end_counter = Ticks::now();
   const Tickspan sweep_time = sweep_end_counter - sweep_start_counter;
-  _total_time_sweeping  += sweep_time;
-  _total_time_this_sweep += sweep_time;
-  _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time);
-  _total_flushed_size += freed_memory;
-  _total_nof_methods_reclaimed += _flushed_count;
-
+  {
+    MutexLockerEx mu(_stat_lock, Mutex::_no_safepoint_check_flag);
+    _total_time_sweeping  += sweep_time;
+    _total_time_this_sweep += sweep_time;
+    _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time);
+    _total_flushed_size += freed_memory;
+    _total_nof_methods_reclaimed += flushed_count;
+    _total_nof_c2_methods_reclaimed += flushed_c2_count;
+    _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
+  }
   EventSweepCodeCache event(UNTIMED);
   if (event.should_commit()) {
     event.set_starttime(sweep_start_counter);
     event.set_endtime(sweep_end_counter);
     event.set_sweepIndex(_traversals);
     event.set_sweptCount(swept_count);
-    event.set_flushedCount(_flushed_count);
-    event.set_markedCount(_marked_for_reclamation_count);
-    event.set_zombifiedCount(_zombified_count);
+    event.set_flushedCount(flushed_count);
+    event.set_markedCount(marked_for_reclamation_count);
+    event.set_zombifiedCount(zombified_count);
     event.commit();
   }
 
@@ -433,7 +457,6 @@
   }
 #endif
 
-  _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
   log_sweep("finished");
 
   // Sweeper is the only case where memory is released, check here if it
@@ -511,10 +534,11 @@
   nm->flush();
 }
 
-int NMethodSweeper::process_nmethod(nmethod* nm) {
+NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) {
+  assert(nm != NULL, "sanity");
   assert(!CodeCache_lock->owned_by_self(), "just checking");
 
-  int freed_memory = 0;
+  MethodStateChange result = None;
   // Make sure this nmethod doesn't get unloaded during the scan,
   // since safepoints may happen during acquired below locks.
   NMethodMarker nmm(nm);
@@ -529,7 +553,7 @@
       nm->cleanup_inline_caches();
       SWEEP(nm);
     }
-    return freed_memory;
+    return result;
   }
 
   if (nm->is_zombie()) {
@@ -541,12 +565,9 @@
       if (PrintMethodFlushing && Verbose) {
         tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm);
       }
-      freed_memory = nm->total_size();
-      if (nm->is_compiled_by_c2()) {
-        _total_nof_c2_methods_reclaimed++;
-      }
       release_nmethod(nm);
-      _flushed_count++;
+      assert(result == None, "sanity");
+      result = Flushed;
     } else {
       if (PrintMethodFlushing && Verbose) {
         tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
@@ -554,8 +575,9 @@
       nm->mark_for_reclamation();
       // Keep track of code cache state change
       _bytes_changed += nm->total_size();
-      _marked_for_reclamation_count++;
       SWEEP(nm);
+      assert(result == None, "sanity");
+      result = MarkedForReclamation;
     }
   } else if (nm->is_not_entrant()) {
     // If there are no current activations of this method on the
@@ -576,8 +598,9 @@
         }
         // Code cache state change is tracked in make_zombie()
         nm->make_zombie();
-        _zombified_count++;
         SWEEP(nm);
+        assert(result == None, "sanity");
+        result = MadeZombie;
       }
       assert(nm->is_zombie(), "nmethod must be zombie");
     } else {
@@ -594,17 +617,15 @@
     if (nm->is_osr_method()) {
       SWEEP(nm);
       // No inline caches will ever point to osr methods, so we can just remove it
-      freed_memory = nm->total_size();
-      if (nm->is_compiled_by_c2()) {
-        _total_nof_c2_methods_reclaimed++;
-      }
       release_nmethod(nm);
-      _flushed_count++;
+      assert(result == None, "sanity");
+      result = Flushed;
     } else {
       // Code cache state change is tracked in make_zombie()
       nm->make_zombie();
-      _zombified_count++;
       SWEEP(nm);
+      assert(result == None, "sanity");
+      result = MadeZombie;
     }
   } else {
     possibly_flush(nm);
@@ -613,7 +634,7 @@
     nm->cleanup_inline_caches();
     SWEEP(nm);
   }
-  return freed_memory;
+  return result;
 }
 
 
--- a/src/share/vm/runtime/sweeper.hpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/runtime/sweeper.hpp	Thu Dec 04 17:53:36 2014 +0000
@@ -56,15 +56,18 @@
 class NMethodSweeper : public AllStatic {
   friend class WhiteBox;
  private:
+  enum MethodStateChange {
+    None,
+    MadeZombie,
+    MarkedForReclamation,
+    Flushed
+  };
   static long      _traversals;                   // Stack scan count, also sweep ID.
   static long      _total_nof_code_cache_sweeps;  // Total number of full sweeps of the code cache
   static long      _time_counter;                 // Virtual time used to periodically invoke sweeper
   static long      _last_sweep;                   // Value of _time_counter when the last sweep happened
   static NMethodIterator _current;                // Current nmethod
   static int       _seen;                         // Nof. nmethod we have currently processed in current pass of CodeCache
-  static int       _flushed_count;                // Nof. nmethods flushed in current sweep
-  static int       _zombified_count;              // Nof. nmethods made zombie in current sweep
-  static int       _marked_for_reclamation_count; // Nof. nmethods marked for reclaim in current sweep
 
   static volatile int  _sweep_started;            // Flag to control conc sweeper
   static volatile bool _should_sweep;             // Indicates if we should invoke the sweeper
@@ -83,8 +86,10 @@
   static Tickspan  _peak_sweep_time;              // Peak time for a full sweep
   static Tickspan  _peak_sweep_fraction_time;     // Peak time sweeping one fraction
 
-  static int  process_nmethod(nmethod *nm);
-  static void release_nmethod(nmethod* nm);
+  static Monitor*  _stat_lock;
+
+  static MethodStateChange process_nmethod(nmethod *nm);
+  static void              release_nmethod(nmethod* nm);
 
   static void init_sweeper_log() NOT_DEBUG_RETURN;
   static bool wait_for_stack_scanning();
--- a/src/share/vm/runtime/thread.cpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/runtime/thread.cpp	Thu Dec 04 17:53:36 2014 +0000
@@ -1076,7 +1076,7 @@
 }
 
 
-void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name,
+void JavaThread::allocate_threadObj(Handle thread_group, const char* thread_name,
                                     bool daemon, TRAPS) {
   assert(thread_group.not_null(), "thread group should be specified");
   assert(threadObj() == NULL, "should only create Java thread object once");
@@ -1123,8 +1123,8 @@
     return;
   }
 
-  KlassHandle group(this, SystemDictionary::ThreadGroup_klass());
-  Handle threadObj(this, this->threadObj());
+  KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
+  Handle threadObj(THREAD, this->threadObj());
 
   JavaCalls::call_special(&result,
                           thread_group,
@@ -1133,8 +1133,6 @@
                           vmSymbols::thread_void_signature(),
                           threadObj,          // Arg 1
                           THREAD);
-
-
 }
 
 // NamedThread --  non-JavaThread subclasses with multiple
--- a/src/share/vm/runtime/thread.hpp	Thu Dec 04 15:09:18 2014 +0100
+++ b/src/share/vm/runtime/thread.hpp	Thu Dec 04 17:53:36 2014 +0000
@@ -749,6 +749,7 @@
 
 class JavaThread: public Thread {
   friend class VMStructs;
+  friend class WhiteBox;
  private:
   JavaThread*    _next;                          // The next thread in the Threads list
   oop            _threadObj;                     // The Java level thread object
@@ -1000,7 +1001,7 @@
   ThreadFunction entry_point() const             { return _entry_point; }
 
   // Allocates a new Java level thread object for this thread. thread_name may be NULL.
-  void allocate_threadObj(Handle thread_group, char* thread_name, bool daemon, TRAPS);
+  void allocate_threadObj(Handle thread_group, const char* thread_name, bool daemon, TRAPS);
 
   // Last frame anchor routines
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/arraycopy/TestArrayCopyNoInit.java	Thu Dec 04 17:53:36 2014 +0000
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2014, 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 8064703
+ * @summary Deoptimization between array allocation and arraycopy may result in non initialized array
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=020 TestArrayCopyNoInit
+ *
+ */
+
+import java.lang.invoke.*;
+
+public class TestArrayCopyNoInit {
+
+    static int[] m1(int[] src) {
+        int[] dest = new int[10];
+        try {
+            System.arraycopy(src, 0, dest, 0, 10);
+        } catch (NullPointerException npe) {
+        }
+        return dest;
+    }
+
+    static int[] m2(Object src, boolean flag) {
+        Class tmp = src.getClass();
+        if (flag) {
+            return null;
+        }
+        int[] dest = new int[10];
+        try {
+            System.arraycopy(src, 0, dest, 0, 10);
+        } catch (ArrayStoreException npe) {
+        }
+        return dest;
+    }
+
+    static int[] m3(int[] src, int src_offset) {
+        int tmp = src[0];
+        int[] dest = new int[10];
+        try {
+            System.arraycopy(src, src_offset, dest, 0, 10);
+        } catch (IndexOutOfBoundsException npe) {
+        }
+        return dest;
+    }
+
+    static int[] m4(int[] src, int length) {
+        int tmp = src[0];
+        int[] dest = new int[10];
+        try {
+            System.arraycopy(src, 0, dest, 0, length);
+        } catch (IndexOutOfBoundsException npe) {
+        }
+        return dest;
+    }
+
+    static TestArrayCopyNoInit[] m5(Object[] src) {
+        Object tmp = src[0];
+        TestArrayCopyNoInit[] dest = new TestArrayCopyNoInit[10];
+        System.arraycopy(src, 0, dest, 0, 0);
+        return dest;
+    }
+
+    static class A {
+    }
+
+    static class B extends A {
+    }
+
+    static class C extends B {
+    }
+
+    static class D extends C {
+    }
+
+    static class E extends D {
+    }
+
+    static class F extends E {
+    }
+
+    static class G extends F {
+    }
+
+    static class H extends G {
+    }
+
+    static class I extends H {
+    }
+
+    static H[] m6(Object[] src) {
+        Object tmp = src[0];
+        H[] dest = new H[10];
+        System.arraycopy(src, 0, dest, 0, 0);
+        return dest;
+    }
+
+    static Object m7_src(Object src) {
+        return src;
+    }
+
+    static int[] m7(Object src, boolean flag) {
+        Class tmp = src.getClass();
+        if (flag) {
+            return null;
+        }
+        src = m7_src(src);
+        int[] dest = new int[10];
+        try {
+            System.arraycopy(src, 0, dest, 0, 10);
+        } catch (ArrayStoreException npe) {
+        }
+        return dest;
+    }
+
+    static public void main(String[] args) throws Throwable {
+        boolean success = true;
+        int[] src = new int[10];
+        TestArrayCopyNoInit[] src2 = new TestArrayCopyNoInit[10];
+        int[] res = null;
+        TestArrayCopyNoInit[] res2 = null;
+        Object src_obj = new Object();
+
+        for (int i = 0; i < 20000; i++) {
+            m1(src);
+        }
+
+        res = m1(null);
+        for (int i = 0; i < res.length; i++) {
+            if (res[i] != 0) {
+                success = false;
+                System.out.println("Uninitialized array following NPE");
+                break;
+            }
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            if ((i%2) == 0) {
+                m2(src, false);
+            } else {
+                m2(src_obj, true);
+            }
+        }
+        res = m2(src_obj, false);
+        for (int i = 0; i < res.length; i++) {
+            if (res[i] != 0) {
+                success = false;
+                System.out.println("Uninitialized array following failed array check");
+                break;
+            }
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            m3(src, 0);
+        }
+        res = m3(src, -1);
+        for (int i = 0; i < res.length; i++) {
+            if (res[i] != 0) {
+                success = false;
+                System.out.println("Uninitialized array following failed src offset check");
+                break;
+            }
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            m4(src, 0);
+        }
+        res = m4(src, -1);
+        for (int i = 0; i < res.length; i++) {
+            if (res[i] != 0) {
+                success = false;
+                System.out.println("Uninitialized array following failed length check");
+                break;
+            }
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            m5(src2);
+        }
+        res2 = m5(new Object[10]);
+        for (int i = 0; i < res2.length; i++) {
+            if (res2[i] != null) {
+                success = false;
+                System.out.println("Uninitialized array following failed type check");
+                break;
+            }
+        }
+
+        H[] src3 = new H[10];
+        I b = new I();
+        for (int i = 0; i < 20000; i++) {
+            m6(src3);
+        }
+        H[] res3 = m6(new Object[10]);
+        for (int i = 0; i < res3.length; i++) {
+            if (res3[i] != null) {
+                success = false;
+                System.out.println("Uninitialized array following failed full type check");
+                break;
+            }
+        }
+
+        for (int i = 0; i < 20000; i++) {
+            if ((i%2) == 0) {
+                m7(src, false);
+            } else {
+                m7(src_obj, true);
+            }
+        }
+        res = m7(src_obj, false);
+        for (int i = 0; i < res.length; i++) {
+            if (res[i] != 0) {
+                success = false;
+                System.out.println("Uninitialized array following failed type check with return value profiling");
+                break;
+            }
+        }
+
+        if (!success) {
+            throw new RuntimeException("Some tests failed");
+        }
+    }
+}
--- a/test/compiler/startup/SmallCodeCacheStartup.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/compiler/startup/SmallCodeCacheStartup.java	Thu Dec 04 17:53:36 2014 +0000
@@ -24,22 +24,29 @@
 /*
  * @test
  * @bug 8023014
- * @summary Test ensures that there is no crash if there is not enough ReservedCodeacacheSize
+ * @summary Test ensures that there is no crash if there is not enough ReservedCodeCacheSize
  *          to initialize all compiler threads. The option -Xcomp gives the VM more time to
- *          to trigger the old bug.
+ *          trigger the old bug.
  * @library /testlibrary
  */
 import com.oracle.java.testlibrary.*;
+import static com.oracle.java.testlibrary.Asserts.assertTrue;
 
 public class SmallCodeCacheStartup {
-  public static void main(String[] args) throws Exception {
-      ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m",
-                                                                "-XX:CICompilerCount=64",
-                                                                "-Xcomp",
-                                                                "-version");
-      OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
-      analyzer.shouldHaveExitValue(0);
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m",
+                                                                  "-XX:CICompilerCount=64",
+                                                                  "-Xcomp",
+                                                                  "-version");
+        OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
+        try {
+            analyzer.shouldHaveExitValue(0);
+        } catch (RuntimeException e) {
+            // Error occurred during initialization, did we run out of adapter space?
+            assertTrue(analyzer.getOutput().contains("VirtualMachineError: Out of space in CodeCache"),
+                    "Expected VirtualMachineError");
+        }
 
-      System.out.println("TEST PASSED");
+        System.out.println("TEST PASSED");
   }
 }
--- a/test/compiler/whitebox/AllocationCodeBlobTest.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/compiler/whitebox/AllocationCodeBlobTest.java	Thu Dec 04 17:53:36 2014 +0000
@@ -29,10 +29,11 @@
 import sun.hotspot.WhiteBox;
 import sun.hotspot.code.BlobType;
 import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.InfiniteLoop;
 
 /*
  * @test AllocationCodeBlobTest
- * @bug 8059624
+ * @bug 8059624 8064669
  * @library /testlibrary /testlibrary/whitebox
  * @build AllocationCodeBlobTest
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -53,11 +54,32 @@
 
     public static void main(String[] args) {
         // check that Sweeper handels dummy blobs correctly
-        new ForcedSweeper(500).start();
+        Thread t = new Thread(
+                new InfiniteLoop(WHITE_BOX::forceNMethodSweep, 1L),
+                "ForcedSweeper");
+        t.setDaemon(true);
+        System.out.println("Starting " + t.getName());
+        t.start();
+
         EnumSet<BlobType> blobTypes = BlobType.getAvailable();
         for (BlobType type : blobTypes) {
             new AllocationCodeBlobTest(type).test();
         }
+
+        // check that deoptimization works well w/ dummy blobs
+        t = new Thread(
+                new InfiniteLoop(WHITE_BOX::deoptimizeAll, 1L),
+                "Deoptimize Thread");
+        t.setDaemon(true);
+        System.out.println("Starting " + t.getName());
+        t.start();
+
+        for (int i = 0; i < 10_000; ++i) {
+            for (BlobType type : blobTypes) {
+                long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
+            }
+        }
+
     }
 
     private final BlobType type;
@@ -105,24 +127,4 @@
     private long getUsage() {
         return bean.getUsage().getUsed();
     }
-
-    private static class ForcedSweeper extends Thread {
-        private final int millis;
-        public ForcedSweeper(int millis) {
-            super("ForcedSweeper");
-            setDaemon(true);
-            this.millis = millis;
-        }
-        public void run() {
-            try {
-                while (true) {
-                    WHITE_BOX.forceNMethodSweep();
-                    Thread.sleep(millis);
-                }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                throw new Error(e);
-            }
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/whitebox/ForceNMethodSweepTest.java	Thu Dec 04 17:53:36 2014 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, 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.lang.reflect.Method;
+import java.util.EnumSet;
+
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.BlobType;
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.InfiniteLoop;
+
+/*
+ * @test
+ * @bug 8059624 8064669
+ * @library /testlibrary /testlibrary/whitebox
+ * @build ForceNMethodSweepTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:-TieredCompilation -XX:+WhiteBoxAPI
+ *                   -XX:CompileCommand=compileonly,SimpleTestCase$Helper::*
+ *                   ForceNMethodSweepTest
+ * @summary testing of WB::forceNMethodSweep
+ */
+public class ForceNMethodSweepTest extends CompilerWhiteBoxTest {
+    public static void main(String[] args) throws Exception {
+        CompilerWhiteBoxTest.main(ForceNMethodSweepTest::new, args);
+    }
+    private final EnumSet<BlobType> blobTypes;
+    private ForceNMethodSweepTest(TestCase testCase) {
+        super(testCase);
+        // to prevent inlining of #method
+        WHITE_BOX.testSetDontInlineMethod(method, true);
+        blobTypes = BlobType.getAvailable();
+    }
+
+    @Override
+    protected void test() throws Exception {
+        checkNotCompiled();
+        guaranteedSweep();
+        int usage = getTotalUsage();
+
+        compile();
+        checkCompiled();
+        int afterCompilation = getTotalUsage();
+        Asserts.assertGT(afterCompilation, usage,
+                "compilation should increase usage");
+
+        guaranteedSweep();
+        int afterSweep = getTotalUsage();
+        Asserts.assertLTE(afterSweep, afterCompilation,
+                "sweep shouldn't increase usage");
+
+        deoptimize();
+        guaranteedSweep();
+        int afterDeoptAndSweep = getTotalUsage();
+        Asserts.assertLT(afterDeoptAndSweep, afterSweep,
+                "sweep after deoptimization should decrease usage");
+     }
+
+    private int getTotalUsage() {
+        int usage = 0;
+        for (BlobType type : blobTypes) {
+           usage += type.getMemoryPool().getUsage().getUsed();
+        }
+        return usage;
+    }
+    private void guaranteedSweep() {
+        // not entrant -> ++stack_traversal_mark -> zombie -> reclamation -> flushed
+        for (int i = 0; i < 5; ++i) {
+            WHITE_BOX.fullGC();
+            WHITE_BOX.forceNMethodSweep();
+        }
+    }
+}
--- a/test/compiler/whitebox/GetNMethodTest.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/compiler/whitebox/GetNMethodTest.java	Thu Dec 04 17:53:36 2014 +0000
@@ -75,7 +75,7 @@
                 break;
             case 2:
             case 3:
-                checkBlockType(nmethod, BlobType.MethodNonProfiled);
+                checkBlockType(nmethod, BlobType.MethodProfiled);
                 break;
             default:
                 throw new Error("unexpected comp level " + nmethod);
--- a/test/testlibrary/com/oracle/java/testlibrary/Asserts.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/testlibrary/com/oracle/java/testlibrary/Asserts.java	Thu Dec 04 17:53:36 2014 +0000
@@ -68,8 +68,7 @@
      * @see #assertLessThan(T, T, String)
      */
     public static <T extends Comparable<T>> void assertLessThan(T lhs, T rhs) {
-        String msg = "Expected that " + format(lhs) + " < " + format(rhs);
-        assertLessThan(lhs, rhs, msg);
+        assertLessThan(lhs, rhs, null);
     }
 
     /**
@@ -81,7 +80,7 @@
      * @throws RuntimeException if the assertion isn't valid.
      */
     public static <T extends Comparable<T>>void assertLessThan(T lhs, T rhs, String msg) {
-        assertTrue(compare(lhs, rhs, msg) < 0, msg);
+        assertTrue(compare(lhs, rhs, msg) < 0, getMessage(lhs, rhs, "<", msg));
     }
 
     /**
@@ -108,8 +107,7 @@
      * @see #assertLessThanOrEqual(T, T, String)
      */
     public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs) {
-        String msg = "Expected that " + format(lhs) + " <= " + format(rhs);
-        assertLessThanOrEqual(lhs, rhs, msg);
+        assertLessThanOrEqual(lhs, rhs, null);
     }
 
     /**
@@ -121,7 +119,7 @@
      * @throws RuntimeException if the assertion isn't valid.
      */
     public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs, String msg) {
-        assertTrue(compare(lhs, rhs, msg) <= 0, msg);
+        assertTrue(compare(lhs, rhs, msg) <= 0, getMessage(lhs, rhs, "<=", msg));
     }
 
     /**
@@ -148,8 +146,7 @@
      * @see #assertEquals(T, T, String)
      */
     public static void assertEquals(Object lhs, Object rhs) {
-        String msg = "Expected " + format(lhs) + " to equal " + format(rhs);
-        assertEquals(lhs, rhs, msg);
+        assertEquals(lhs, rhs, null);
     }
 
     /**
@@ -166,7 +163,7 @@
                 error(msg);
             }
         } else {
-            assertTrue(lhs.equals(rhs), msg);
+            assertTrue(lhs.equals(rhs), getMessage(lhs, rhs, "==", msg));
         }
     }
 
@@ -194,8 +191,7 @@
      * @see #assertGreaterThanOrEqual(T, T, String)
      */
     public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs) {
-        String msg = "Expected that " + format(lhs) + " >= " + format(rhs);
-        assertGreaterThanOrEqual(lhs, rhs, msg);
+        assertGreaterThanOrEqual(lhs, rhs, null);
     }
 
     /**
@@ -207,7 +203,7 @@
      * @throws RuntimeException if the assertion isn't valid.
      */
     public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs, String msg) {
-        assertTrue(compare(lhs, rhs, msg) >= 0, msg);
+        assertTrue(compare(lhs, rhs, msg) >= 0, getMessage(lhs, rhs, ">=", msg));
     }
 
     /**
@@ -234,8 +230,7 @@
      * @see #assertGreaterThan(T, T, String)
      */
     public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs) {
-        String msg = "Expected that " + format(lhs) + " > " + format(rhs);
-        assertGreaterThan(lhs, rhs, msg);
+        assertGreaterThan(lhs, rhs, null);
     }
 
     /**
@@ -247,7 +242,7 @@
      * @throws RuntimeException if the assertion isn't valid.
      */
     public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs, String msg) {
-        assertTrue(compare(lhs, rhs, msg) > 0, msg);
+        assertTrue(compare(lhs, rhs, msg) > 0, getMessage(lhs, rhs, ">", msg));
     }
 
     /**
@@ -274,8 +269,7 @@
      * @see #assertNotEquals(T, T, String)
      */
     public static void assertNotEquals(Object lhs, Object rhs) {
-        String msg = "Expected " + format(lhs) + " to not equal " + format(rhs);
-        assertNotEquals(lhs, rhs, msg);
+        assertNotEquals(lhs, rhs, null);
     }
 
     /**
@@ -292,7 +286,7 @@
                 error(msg);
             }
         } else {
-            assertFalse(lhs.equals(rhs), msg);
+            assertFalse(lhs.equals(rhs), getMessage(lhs, rhs,"!=", msg));
         }
     }
 
@@ -450,4 +444,8 @@
         throw new RuntimeException(msg);
     }
 
+    private static String getMessage(Object lhs, Object rhs, String op, String msg) {
+        return (msg == null ? "" : msg + " ") + "(assert failed: " + format(lhs) + " " + op +  " " + format(rhs) + ")";
+    }
 }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/com/oracle/java/testlibrary/InfiniteLoop.java	Thu Dec 04 17:53:36 2014 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.util.Objects;
+
+/**
+ * Class which runs another Runnable in infinite loop with certain pauses
+ * between cycles.
+ */
+public class InfiniteLoop implements Runnable {
+    private final Runnable target;
+    private final long mills;
+
+
+    /**
+     * @param target a target to run in a loop
+     * @param mills  the length of pause time in milliseconds
+     * @throws NullPointerException if target is null
+     * @throws IllegalArgumentException if the value of millis is negative
+     */
+    public InfiniteLoop(Runnable target, long mills) {
+        Objects.requireNonNull(target);
+        if (mills < 0) {
+            throw new IllegalArgumentException("mills < 0");
+        }
+        this.target = target;
+        this.mills = mills;
+    }
+
+    @Override
+    public void run() {
+        try {
+            while (true) {
+                target.run();
+                Thread.sleep(mills);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new Error(e);
+        }
+    }
+}
--- a/test/testlibrary/com/oracle/java/testlibrary/Platform.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/testlibrary/com/oracle/java/testlibrary/Platform.java	Thu Dec 04 17:53:36 2014 +0000
@@ -23,6 +23,7 @@
 
 package com.oracle.java.testlibrary;
 
+import java.util.regex.Pattern;
 import com.oracle.java.testlibrary.Utils;
 
 public class Platform {
@@ -97,29 +98,31 @@
 
     // Returns true for sparc and sparcv9.
     public static boolean isSparc() {
-        return isArch("sparc");
+        return isArch("sparc.*");
     }
 
     public static boolean isARM() {
-        return isArch("arm");
+        return isArch("arm.*");
     }
 
     public static boolean isPPC() {
-        return isArch("ppc");
+        return isArch("ppc.*");
     }
 
     public static boolean isX86() {
-        // On Linux it's 'i386', Windows 'x86'
-        return (isArch("i386") || isArch("x86"));
+        // On Linux it's 'i386', Windows 'x86' without '_64' suffix.
+        return isArch("(i386)|(x86(?!_64))");
     }
 
     public static boolean isX64() {
         // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64'
-        return (isArch("amd64") || isArch("x86_64"));
+        return isArch("(amd64)|(x86_64)");
     }
 
-    private static boolean isArch(String archname) {
-        return osArch.toLowerCase().startsWith(archname.toLowerCase());
+    private static boolean isArch(String archnameRE) {
+        return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
+                .matcher(osArch)
+                .matches();
     }
 
     public static String getOsArch() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/com/oracle/java/testlibrary/TimeLimitedRunner.java	Thu Dec 04 17:53:36 2014 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.util.Objects;
+import java.util.concurrent.Callable;
+
+/**
+ * Auxiliary class to run target w/ given timeout.
+ */
+public class TimeLimitedRunner implements Callable<Void> {
+    private final long              stoptime;
+    private final long              timeout;
+    private final double            factor;
+    private final Callable<Boolean> target;
+
+    /**
+     * @param timeout   a timeout. zero means no time limitation
+     * @param factor    a multiplier used to estimate next iteration time
+     * @param target    a target to run
+     * @throws NullPointerException     if target is null
+     * @throws IllegalArgumentException if timeout is negative or
+                                        factor isn't positive
+     */
+    public TimeLimitedRunner(long timeout, double factor,
+            Callable<Boolean> target) {
+        Objects.requireNonNull(target, "target must not be null");
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout[" + timeout + "] < 0");
+        }
+        if (factor <= 0d) {
+            throw new IllegalArgumentException("factor[" + factor + "] <= 0");
+        }
+        this.stoptime = System.currentTimeMillis() + timeout;
+        this.timeout = timeout;
+        this.factor = factor;
+        this.target = target;
+    }
+
+    /**
+     * Runs @{linkplan target} while it returns true and timeout isn't exceeded
+     */
+    @Override
+    public Void call() throws Exception {
+        long maxDuration = 0L;
+        long iterStart = System.currentTimeMillis();
+        if (timeout != 0 && iterStart > stoptime) {
+            return null;
+        }
+        while (target.call()) {
+            if (timeout != 0) {
+                long iterDuration = System.currentTimeMillis() - iterStart;
+                maxDuration = Math.max(maxDuration, iterDuration);
+                iterStart = System.currentTimeMillis();
+                if (iterStart + (maxDuration * factor) > stoptime) {
+                    System.out.println("Not enough time to continue execution. "
+                            + "Interrupted.");
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+}
--- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu Dec 04 15:09:18 2014 +0100
+++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu Dec 04 17:53:36 2014 +0000
@@ -154,7 +154,14 @@
   public native Object[] getNMethod(Executable method, boolean isOsr);
   public native long    allocateCodeBlob(int size, int type);
   public native void    freeCodeBlob(long addr);
-  public native void    forceNMethodSweep();
+  public        void    forceNMethodSweep() {
+    try {
+        forceNMethodSweep0().join();
+    } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
+    }
+  }
+  public native Thread  forceNMethodSweep0();
   public native Object[] getCodeHeapEntries(int type);
   public native int     getCompilationActivityMode();
   public native Object[] getCodeBlob(long addr);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java	Thu Dec 04 17:53:36 2014 +0000
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Platform;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @test
+ * @summary Verify that for each group of mutually exclusive predicates defined
+ *          in com.oracle.java.testlibrary.Platform one and only one predicate
+ *          evaluates to true.
+ * @library /testlibrary
+ * @run main TestMutuallyExclusivePlatformPredicates
+ */
+public class TestMutuallyExclusivePlatformPredicates {
+    private static enum MethodGroup {
+        ARCH("isARM", "isPPC", "isSparc", "isX86", "isX64"),
+        BITNESS("is32bit", "is64bit"),
+        OS("isLinux", "isSolaris", "isWindows", "isOSX"),
+        VM_TYPE("isClient", "isServer", "isGraal", "isMinimal"),
+        IGNORED("isEmbedded", "isDebugBuild");
+
+        public final List<String> methodNames;
+
+        private MethodGroup(String... methodNames) {
+            this.methodNames = Collections.unmodifiableList(
+                    Arrays.asList(methodNames));
+        }
+    }
+
+    public static void main(String args[]) {
+        EnumSet<MethodGroup> notIgnoredMethodGroups
+                = EnumSet.complementOf(EnumSet.of(MethodGroup.IGNORED));
+
+        notIgnoredMethodGroups.forEach(
+                TestMutuallyExclusivePlatformPredicates::verifyPredicates);
+
+        TestMutuallyExclusivePlatformPredicates.verifyCoverage();
+    }
+
+    /**
+     * Verifies that one and only one predicate method defined in
+     * {@link com.oracle.java.testlibrary.Platform}, whose name included into
+     * methodGroup will return {@code true}.
+     * @param methodGroup The group of methods that should be tested.
+     */
+    private static void verifyPredicates(MethodGroup methodGroup) {
+        System.out.println("Verifying method group: " + methodGroup.name());
+        long truePredicatesCount = methodGroup.methodNames.stream()
+                .filter(TestMutuallyExclusivePlatformPredicates
+                        ::evaluatePredicate)
+                .count();
+
+        Asserts.assertEQ(truePredicatesCount, 1L, String.format(
+                "Only one predicate from group %s should be evaluated to true "
+                        + "(Actually %d predicates were evaluated to true).",
+                methodGroup.name(), truePredicatesCount));
+    }
+
+    /**
+     * Verifies that all predicates defined in
+     * {@link com.oracle.java.testlibrary.Platform} were either tested or
+     * explicitly ignored.
+     */
+    private static void verifyCoverage() {
+        Set<String> allMethods = new HashSet<>();
+        for (MethodGroup group : MethodGroup.values()) {
+            allMethods.addAll(group.methodNames);
+        }
+
+        for (Method m : Platform.class.getMethods()) {
+            if (m.getParameterCount() == 0
+                    && m.getReturnType() == boolean.class) {
+                Asserts.assertTrue(allMethods.contains(m.getName()),
+                        "All Platform's methods with signature '():Z' should "
+                                + "be tested ");
+            }
+        }
+    }
+
+    /**
+     * Evaluates predicate method with name {@code name} defined in
+     * {@link com.oracle.java.testlibrary.Platform}.
+     *
+     * @param name The name of a predicate to be evaluated.
+     * @return evaluated predicate's value.
+     * @throws java.lang.Error if predicate is not defined or could not be
+     *                         evaluated.
+     */
+    private static boolean evaluatePredicate(String name) {
+        try {
+            System.out.printf("Trying to evaluate predicate with name %s%n",
+                    name);
+            boolean value
+                    = (Boolean) Platform.class.getMethod(name).invoke(null);
+            System.out.printf("Predicate evaluated to: %s%n", value);
+            return value;
+        } catch (NoSuchMethodException e) {
+            throw new Error("Predicate with name " + name
+                    + " is not defined in " + Platform.class.getName(), e);
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new Error("Unable to evaluate predicate " + name, e);
+        }
+    }
+}