changeset 27645:8fe155d119af

Merge
author drchase
date Thu, 13 Nov 2014 11:35:15 -0500
parents 2d749ba03ff5 f4aa22a934e4
children 74c92bdda9b5
files hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp hotspot/src/share/vm/opto/macro.cpp hotspot/src/share/vm/runtime/mutexLocker.cpp hotspot/src/share/vm/runtime/mutexLocker.hpp hotspot/test/TEST.groups hotspot/test/compiler/7068051/Test7068051.sh hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java
diffstat 44 files changed, 925 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -1767,7 +1767,7 @@
     // at [FETCH], below, will never observe a biased encoding (*101b).
     // If this invariant is not held we risk exclusion (safety) failure.
     if (UseBiasedLocking && !UseOptoBiasInlining) {
-      biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters);
+      biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, counters);
     }
 
 #if INCLUDE_RTM_OPT
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -68,7 +68,10 @@
 // ciMethod::ciMethod
 //
 // Loaded method.
-ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) {
+ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
+  ciMetadata(h_m()),
+  _holder(holder)
+{
   assert(h_m() != NULL, "no null method");
 
   // These fields are always filled in in loaded methods.
@@ -124,7 +127,6 @@
   // generating _signature may allow GC and therefore move m.
   // These fields are always filled in.
   _name = env->get_symbol(h_m()->name());
-  _holder = env->get_instance_klass(h_m()->method_holder());
   ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
   constantPoolHandle cpool = h_m()->constants();
   _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -91,7 +91,7 @@
   BCEscapeAnalyzer*   _bcea;
 #endif
 
-  ciMethod(methodHandle h_m);
+  ciMethod(methodHandle h_m, ciInstanceKlass* holder);
   ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor);
 
   Method* get_Method() const {
--- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -239,7 +239,7 @@
 ciObject* ciObjectFactory::get(oop key) {
   ASSERT_IN_VM;
 
-  assert(key == NULL || Universe::heap()->is_in_reserved(key), "must be");
+  assert(Universe::heap()->is_in_reserved(key), "must be");
 
   NonPermObject* &bucket = find_non_perm(key);
   if (bucket != NULL) {
@@ -260,10 +260,10 @@
 }
 
 // ------------------------------------------------------------------
-// ciObjectFactory::get
+// ciObjectFactory::get_metadata
 //
-// Get the ciObject corresponding to some oop.  If the ciObject has
-// already been created, it is returned.  Otherwise, a new ciObject
+// Get the ciMetadata corresponding to some Metadata. If the ciMetadata has
+// already been created, it is returned. Otherwise, a new ciMetadata
 // is created.
 ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
   ASSERT_IN_VM;
@@ -290,9 +290,9 @@
   }
 #endif
   if (!is_found_at(index, key, _ci_metadata)) {
-    // The ciObject does not yet exist.  Create it and insert it
+    // The ciMetadata does not yet exist. Create it and insert it
     // into the cache.
-    ciMetadata* new_object = create_new_object(key);
+    ciMetadata* new_object = create_new_metadata(key);
     init_ident_of(new_object);
     assert(new_object->is_metadata(), "must be");
 
@@ -344,15 +344,28 @@
 }
 
 // ------------------------------------------------------------------
-// ciObjectFactory::create_new_object
+// ciObjectFactory::create_new_metadata
 //
-// Create a new ciObject from a Metadata*.
+// Create a new ciMetadata from a Metadata*.
 //
-// Implementation note: this functionality could be virtual behavior
-// of the oop itself.  For now, we explicitly marshal the object.
-ciMetadata* ciObjectFactory::create_new_object(Metadata* o) {
+// Implementation note: in order to keep Metadata live, an auxiliary ciObject
+// is used, which points to it's holder.
+ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) {
   EXCEPTION_CONTEXT;
 
+  // Hold metadata from unloading by keeping it's holder alive.
+  if (_initialized && o->is_klass()) {
+    Klass* holder = ((Klass*)o);
+    if (holder->oop_is_instance() && InstanceKlass::cast(holder)->is_anonymous()) {
+      // Though ciInstanceKlass records class loader oop, it's not enough to keep
+      // VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
+      // It is enough to record a ciObject, since cached elements are never removed
+      // during ciObjectFactory lifetime. ciObjectFactory itself is created for
+      // every compilation and lives for the whole duration of the compilation.
+      ciObject* h = get(holder->klass_holder());
+    }
+  }
+
   if (o->is_klass()) {
     KlassHandle h_k(THREAD, (Klass*)o);
     Klass* k = (Klass*)o;
@@ -365,14 +378,16 @@
     }
   } else if (o->is_method()) {
     methodHandle h_m(THREAD, (Method*)o);
-    return new (arena()) ciMethod(h_m);
+    ciEnv *env = CURRENT_THREAD_ENV;
+    ciInstanceKlass* holder = env->get_instance_klass(h_m()->method_holder());
+    return new (arena()) ciMethod(h_m, holder);
   } else if (o->is_methodData()) {
     // Hold methodHandle alive - might not be necessary ???
     methodHandle h_m(THREAD, ((MethodData*)o)->method());
     return new (arena()) ciMethodData((MethodData*)o);
   }
 
-  // The oop is of some type not supported by the compiler interface.
+  // The Metadata* is of some type not supported by the compiler interface.
   ShouldNotReachHere();
   return NULL;
 }
@@ -701,7 +716,7 @@
 // If there is no entry in the cache corresponding to this oop, return
 // the null tail of the bucket into which the oop should be inserted.
 ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) {
-  assert(Universe::heap()->is_in_reserved_or_null(key), "must be");
+  assert(Universe::heap()->is_in_reserved(key), "must be");
   ciMetadata* klass = get_metadata(key->klass());
   NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS];
   for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) {
--- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -73,7 +73,7 @@
   void insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects);
 
   ciObject* create_new_object(oop o);
-  ciMetadata* create_new_object(Metadata* o);
+  ciMetadata* create_new_metadata(Metadata* o);
 
   void ensure_metadata_alive(ciMetadata* m);
 
--- a/hotspot/src/share/vm/code/codeBlob.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/code/codeBlob.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -43,7 +43,7 @@
 #include "c1/c1_Runtime1.hpp"
 #endif
 
-unsigned int align_code_offset(int offset) {
+unsigned int CodeBlob::align_code_offset(int offset) {
   // align the size to CodeEntryAlignment
   return
     ((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1))
--- a/hotspot/src/share/vm/code/codeBlob.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/code/codeBlob.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -83,6 +83,7 @@
  public:
   // Returns the space needed for CodeBlob
   static unsigned int allocation_size(CodeBuffer* cb, int header_size);
+  static unsigned int align_code_offset(int offset);
 
   // Creation
   // a) simple CodeBlob
@@ -207,7 +208,7 @@
   }
 };
 
-
+class WhiteBox;
 //----------------------------------------------------------------------------------------------------
 // BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc.
 
@@ -215,6 +216,7 @@
   friend class VMStructs;
   friend class AdapterBlob;
   friend class MethodHandlesAdapterBlob;
+  friend class WhiteBox;
 
  private:
   // Creation support
--- a/hotspot/src/share/vm/code/codeCache.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -305,7 +305,7 @@
   MemoryService::add_code_heap_memory_pool(heap, name);
 }
 
-CodeHeap* CodeCache::get_code_heap(CodeBlob* cb) {
+CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) {
   assert(cb != NULL, "CodeBlob is null");
   FOR_ALL_HEAPS(heap) {
     if ((*heap)->contains(cb)) {
--- a/hotspot/src/share/vm/code/codeCache.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/code/codeCache.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -77,6 +77,7 @@
 class CodeCache : AllStatic {
   friend class VMStructs;
   friend class NMethodIterator;
+  friend class WhiteBox;
  private:
   // CodeHeaps of the cache
   static GrowableArray<CodeHeap*>* _heaps;
@@ -98,7 +99,7 @@
   static void initialize_heaps();                             // Initializes the CodeHeaps
   // Creates a new heap with the given name and size, containing CodeBlobs of the given type
   static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type);
-  static CodeHeap* get_code_heap(CodeBlob* cb);               // Returns the CodeHeap for the given CodeBlob
+  static CodeHeap* get_code_heap(const CodeBlob* cb);         // Returns the CodeHeap for the given CodeBlob
   static CodeHeap* get_code_heap(int code_blob_type);         // Returns the CodeHeap for the given CodeBlobType
   // Returns the name of the VM option to set the size of the corresponding CodeHeap
   static const char* get_code_heap_flag_name(int code_blob_type);
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -35,6 +35,7 @@
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/nativeLookup.hpp"
+#include "prims/whitebox.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/atomic.inline.hpp"
 #include "runtime/compilationPolicy.hpp"
@@ -1963,6 +1964,12 @@
     if (comp == NULL) {
       ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
     } else {
+      if (WhiteBoxAPI && WhiteBox::compilation_locked) {
+        MonitorLockerEx locker(Compilation_lock, Mutex::_no_safepoint_check_flag);
+        while (WhiteBox::compilation_locked) {
+          locker.wait(Mutex::_no_safepoint_check_flag);
+        }
+      }
       comp->compile_method(&ci_env, target, osr_bci);
     }
 
--- a/hotspot/src/share/vm/interpreter/bytecodes.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -401,8 +401,10 @@
   static bool        is_astore      (Code code)    { return (code == _astore || code == _astore_0 || code == _astore_1
                                                                              || code == _astore_2 || code == _astore_3); }
 
+  static bool        is_const       (Code code)    { return (_aconst_null <= code && code <= _ldc2_w); }
   static bool        is_zero_const  (Code code)    { return (code == _aconst_null || code == _iconst_0
                                                            || code == _fconst_0 || code == _dconst_0); }
+  static bool        is_return      (Code code)    { return (_ireturn <= code && code <= _return); }
   static bool        is_invoke      (Code code)    { return (_invokevirtual <= code && code <= _invokedynamic); }
   static bool        has_receiver   (Code code)    { assert(is_invoke(code), "");  return code == _invokevirtual ||
                                                                                           code == _invokespecial ||
--- a/hotspot/src/share/vm/oops/method.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/oops/method.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -588,6 +588,15 @@
   return true;
 }
 
+bool Method::is_constant_getter() const {
+  int last_index = code_size() - 1;
+  // Check if the first 1-3 bytecodes are a constant push
+  // and the last bytecode is a return.
+  return (2 <= code_size() && code_size() <= 4 &&
+          Bytecodes::is_const(java_code_at(0)) &&
+          Bytecodes::length_for(java_code_at(0)) == last_index &&
+          Bytecodes::is_return(java_code_at(last_index)));
+}
 
 bool Method::is_initializer() const {
   return name() == vmSymbols::object_initializer_name() || is_static_initializer();
--- a/hotspot/src/share/vm/oops/method.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/oops/method.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -595,6 +595,9 @@
   // returns true if the method is an accessor function (setter/getter).
   bool is_accessor() const;
 
+  // returns true if the method does nothing but return a constant of primitive type
+  bool is_constant_getter() const;
+
   // returns true if the method is an initializer (<init> or <clinit>).
   bool is_initializer() const;
 
--- a/hotspot/src/share/vm/oops/methodData.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/oops/methodData.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -1134,7 +1134,7 @@
   _tenure_traps = 0;
   _num_loops = 0;
   _num_blocks = 0;
-  _would_profile = true;
+  _would_profile = unknown;
 
 #if INCLUDE_RTM_OPT
   _rtm_state = NoRTM; // No RTM lock eliding by default
--- a/hotspot/src/share/vm/oops/methodData.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/oops/methodData.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -2096,7 +2096,8 @@
   short             _num_loops;
   short             _num_blocks;
   // Does this method contain anything worth profiling?
-  bool              _would_profile;
+  enum WouldProfile {unknown, no_profile, profile};
+  WouldProfile      _would_profile;
 
   // Size of _data array in bytes.  (Excludes header and extra_data fields.)
   int _data_size;
@@ -2270,8 +2271,8 @@
   }
 #endif
 
-  void set_would_profile(bool p)              { _would_profile = p;    }
-  bool would_profile() const                  { return _would_profile; }
+  void set_would_profile(bool p)              { _would_profile = p ? profile : no_profile; }
+  bool would_profile() const                  { return _would_profile != no_profile; }
 
   int num_loops() const                       { return _num_loops;  }
   void set_num_loops(int n)                   { _num_loops = n;     }
--- a/hotspot/src/share/vm/opto/doCall.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/doCall.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -794,7 +794,7 @@
   Node* ex_klass_node = NULL;
   if (has_ex_handler() && !ex_type->klass_is_exact()) {
     Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
-    ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
+    ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
 
     // Compute the exception klass a little more cleverly.
     // Obvious solution is to simple do a LoadKlass from the 'ex_node'.
@@ -812,7 +812,7 @@
           continue;
         }
         Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes());
-        Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
+        Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
         ex_klass_node->init_req( i, k );
       }
       _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
--- a/hotspot/src/share/vm/opto/graphKit.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -1154,7 +1154,7 @@
   Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
   if (akls != NULL)  return akls;
   Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
-  return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) );
+  return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
 }
 
 //-------------------------load_array_length-----------------------------------
@@ -2615,7 +2615,7 @@
   // types load from the super-class display table which is immutable.
   m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr()));
   Node *kmem = might_be_cache ? m : C->immutable_memory();
-  Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
+  Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, NULL, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
 
   // Compile speed common case: ARE a subtype and we canNOT fail
   if( superklass == nkls )
--- a/hotspot/src/share/vm/opto/library_call.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -3345,7 +3345,7 @@
   if (region == NULL)  never_see_null = true;
   Node* p = basic_plus_adr(mirror, offset);
   const TypeKlassPtr*  kls_type = TypeKlassPtr::OBJECT_OR_NULL;
-  Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
+  Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
   Node* null_ctl = top();
   kls = null_check_oop(kls, &null_ctl, never_see_null);
   if (region != NULL) {
@@ -3517,7 +3517,7 @@
       phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
     // If we fall through, it's a plain class.  Get its _super.
     p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
-    kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
+    kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
     null_ctl = top();
     kls = null_check_oop(kls, &null_ctl);
     if (null_ctl != top()) {
@@ -3671,7 +3671,7 @@
     args[which_arg] = arg;
 
     Node* p = basic_plus_adr(arg, class_klass_offset);
-    Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type);
+    Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type);
     klasses[which_arg] = _gvn.transform(kls);
   }
 
--- a/hotspot/src/share/vm/opto/macro.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/macro.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -2201,7 +2201,7 @@
     Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn);
     if (klass_node == NULL) {
       Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
-      klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) );
+      klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr()));
 #ifdef _LP64
       if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) {
         assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity");
--- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -529,7 +529,7 @@
       // (At this point we can assume disjoint_bases, since types differ.)
       int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
       Node* p1 = basic_plus_adr(dest_klass, ek_offset);
-      Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
+      Node* n1 = LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
       Node* dest_elem_klass = transform_later(n1);
       Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem,
                                               adr_type,
--- a/hotspot/src/share/vm/opto/memnode.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -861,6 +861,10 @@
 
 
 //=============================================================================
+// Should LoadNode::Ideal() attempt to remove control edges?
+bool LoadNode::can_remove_control() const {
+  return true;
+}
 uint LoadNode::size_of() const { return sizeof(*this); }
 uint LoadNode::cmp( const Node &n ) const
 { return !Type::cmp( _type, ((LoadNode&)n)._type ); }
@@ -1471,7 +1475,7 @@
 }
 
 //------------------------------Ideal------------------------------------------
-// If the load is from Field memory and the pointer is non-null, we can
+// If the load is from Field memory and the pointer is non-null, it might be possible to
 // zero out the control input.
 // If the offset is constant and the base is an object allocation,
 // try to hook me up to the exact initializing store.
@@ -1498,6 +1502,7 @@
       && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
     // Check for useless control edge in some common special cases
     if (in(MemNode::Control) != NULL
+        && can_remove_control()
         && phase->type(base)->higher_equal(TypePtr::NOTNULL)
         && all_controls_dominate(base, phase->C->start())) {
       // A method-invariant, non-null address (constant or 'this' argument).
@@ -2019,8 +2024,7 @@
 //=============================================================================
 //----------------------------LoadKlassNode::make------------------------------
 // Polymorphic factory method:
-Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) {
-  Node *ctl = NULL;
+Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) {
   // sanity check the alias category against the created node type
   const TypePtr *adr_type = adr->bottom_type()->isa_ptr();
   assert(adr_type != NULL, "expecting TypeKlassPtr");
@@ -2040,6 +2044,12 @@
   return klass_value_common(phase);
 }
 
+// In most cases, LoadKlassNode does not have the control input set. If the control
+// input is set, it must not be removed (by LoadNode::Ideal()).
+bool LoadKlassNode::can_remove_control() const {
+  return false;
+}
+
 const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const {
   // Either input is TOP ==> the result is TOP
   const Type *t1 = phase->type( in(MemNode::Memory) );
--- a/hotspot/src/share/vm/opto/memnode.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -148,6 +148,8 @@
 protected:
   virtual uint cmp(const Node &n) const;
   virtual uint size_of() const; // Size is bigger
+  // Should LoadNode::Ideal() attempt to remove control edges?
+  virtual bool can_remove_control() const;
   const Type* const _type;      // What kind of value is loaded?
 public:
 
@@ -171,8 +173,10 @@
   // we are equivalent to.  We look for Load of a Store.
   virtual Node *Identity( PhaseTransform *phase );
 
-  // If the load is from Field memory and the pointer is non-null, we can
+  // If the load is from Field memory and the pointer is non-null, it might be possible to
   // zero out the control input.
+  // If the offset is constant and the base is an object allocation,
+  // try to hook me up to the exact initializing store.
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 
   // Split instance field load through Phi.
@@ -431,6 +435,10 @@
 //------------------------------LoadKlassNode----------------------------------
 // Load a Klass from an object
 class LoadKlassNode : public LoadPNode {
+protected:
+  // In most cases, LoadKlassNode does not have the control input set. If the control
+  // input is set, it must not be removed (by LoadNode::Ideal()).
+  virtual bool can_remove_control() const;
 public:
   LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo)
     : LoadPNode(c, mem, adr, at, tk, mo) {}
@@ -440,8 +448,8 @@
   virtual bool depends_only_on_test() const { return true; }
 
   // Polymorphic factory method:
-  static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at,
-                     const TypeKlassPtr *tk = TypeKlassPtr::OBJECT );
+  static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at,
+                    const TypeKlassPtr* tk = TypeKlassPtr::OBJECT);
 };
 
 //------------------------------LoadNKlassNode---------------------------------
--- a/hotspot/src/share/vm/opto/parse1.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/parse1.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -1987,7 +1987,7 @@
   // finalization.  In general this will fold up since the concrete
   // class is often visible so the access flags are constant.
   Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
-  Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) );
+  Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS));
 
   Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset()));
   Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered);
--- a/hotspot/src/share/vm/opto/parseHelper.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -156,22 +156,43 @@
   int klass_offset = oopDesc::klass_offset_in_bytes();
   Node* p = basic_plus_adr( ary, ary, klass_offset );
   // p's type is array-of-OOPS plus klass_offset
-  Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) );
+  Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS));
   // Get the array klass
   const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
 
-  // array_klass's type is generally INexact array-of-oop.  Heroically
-  // cast the array klass to EXACT array and uncommon-trap if the cast
-  // fails.
+  // The type of array_klass is usually INexact array-of-oop.  Heroically
+  // cast array_klass to EXACT array and uncommon-trap if the cast fails.
+  // Make constant out of the inexact array klass, but use it only if the cast
+  // succeeds.
   bool always_see_exact_class = false;
   if (MonomorphicArrayCheck
-      && !too_many_traps(Deoptimization::Reason_array_check)) {
+      && !too_many_traps(Deoptimization::Reason_array_check)
+      && !tak->klass_is_exact()
+      && tak != TypeKlassPtr::OBJECT) {
+      // Regarding the fourth condition in the if-statement from above:
+      //
+      // If the compiler has determined that the type of array 'ary' (represented
+      // by 'array_klass') is java/lang/Object, the compiler must not assume that
+      // the array 'ary' is monomorphic.
+      //
+      // If 'ary' were of type java/lang/Object, this arraystore would have to fail,
+      // because it is not possible to perform a arraystore into an object that is not
+      // a "proper" array.
+      //
+      // Therefore, let's obtain at runtime the type of 'ary' and check if we can still
+      // successfully perform the store.
+      //
+      // The implementation reasons for the condition are the following:
+      //
+      // java/lang/Object is the superclass of all arrays, but it is represented by the VM
+      // as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect
+      // 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses.
+      //
+      // See issue JDK-8057622 for details.
+
     always_see_exact_class = true;
     // (If no MDO at all, hope for the best, until a trap actually occurs.)
-  }
 
-  // Is the array klass is exactly its defined type?
-  if (always_see_exact_class && !tak->klass_is_exact()) {
     // Make a constant out of the inexact array klass
     const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr();
     Node* con = makecon(extak);
@@ -202,11 +223,15 @@
   // Extract the array element class
   int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
   Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
-  Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) );
+  // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true,
+  // we must set a control edge from the IfTrue node created by the uncommon_trap above to the
+  // LoadKlassNode.
+  Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL,
+                                                       immutable_memory(), p2, tak));
 
   // Check (the hard way) and throw if not a subklass.
   // Result is ignored, we just need the CFG effects.
-  gen_checkcast( obj, a_e_klass );
+  gen_checkcast(obj, a_e_klass);
 }
 
 
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -24,6 +24,8 @@
 
 #include "precompiled.hpp"
 
+#include <new>
+
 #include "code/codeCache.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/universe.hpp"
@@ -37,9 +39,11 @@
 
 #include "runtime/thread.hpp"
 #include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
 #include "runtime/interfaceSupport.hpp"
 #include "runtime/os.hpp"
 #include "runtime/vm_version.hpp"
+#include "runtime/sweeper.hpp"
 
 #include "utilities/array.hpp"
 #include "utilities/debug.hpp"
@@ -67,6 +71,7 @@
 #define SIZE_T_MAX_VALUE ((size_t) -1)
 
 bool WhiteBox::_used = false;
+volatile bool WhiteBox::compilation_locked = false;
 
 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
   return (jlong)(void*)JNIHandles::resolve(obj);
@@ -302,13 +307,12 @@
 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
   jlong addr = 0;
 
-    addr = (jlong)(uintptr_t)os::reserve_memory(size);
-    MemTracker::record_virtual_memory_type((address)addr, mtTest);
+  addr = (jlong)(uintptr_t)os::reserve_memory(size);
+  MemTracker::record_virtual_memory_type((address)addr, mtTest);
 
   return addr;
 WB_END
 
-
 WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
   os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem);
   MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
@@ -728,6 +732,29 @@
 WB_END
 
 
+WB_ENTRY(void, WB_LockCompilation(JNIEnv* env, jobject o, jlong timeout))
+  WhiteBox::compilation_locked = true;
+WB_END
+
+WB_ENTRY(void, WB_UnlockCompilation(JNIEnv* env, jobject o))
+  MonitorLockerEx mo(Compilation_lock, Mutex::_no_safepoint_check_flag);
+  WhiteBox::compilation_locked = false;
+  mo.notify_all();
+WB_END
+
+void WhiteBox::force_sweep() {
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    NMethodSweeper::_should_sweep = true;
+  }
+  NMethodSweeper::possibly_sweep();
+}
+
+WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
+  WhiteBox::force_sweep();
+WB_END
+
 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
   ResourceMark rm(THREAD);
   int len;
@@ -774,6 +801,46 @@
   return features_string;
 WB_END
 
+int WhiteBox::get_blob_type(const CodeBlob* code) {
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to 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");
+  return CodeCache::get_code_heap(blob_type);
+}
+
+struct CodeBlobStub {
+  CodeBlobStub(const CodeBlob* blob) :
+      name(os::strdup(blob->name())),
+      size(blob->size()),
+      blob_type(WhiteBox::get_blob_type(blob)) { }
+  ~CodeBlobStub() { os::free((void*) name); }
+  const char* const name;
+  const int         size;
+  const int         blob_type;
+};
+
+static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) {
+  jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
+  CHECK_JNI_EXCEPTION_(env, NULL);
+  jobjectArray result = env->NewObjectArray(3, clazz, NULL);
+
+  jstring name = env->NewStringUTF(cb->name);
+  CHECK_JNI_EXCEPTION_(env, NULL);
+  env->SetObjectArrayElement(result, 0, name);
+
+  jobject obj = integerBox(thread, env, cb->size);
+  CHECK_JNI_EXCEPTION_(env, NULL);
+  env->SetObjectArrayElement(result, 1, obj);
+
+  obj = integerBox(thread, env, cb->blob_type);
+  CHECK_JNI_EXCEPTION_(env, NULL);
+  env->SetObjectArrayElement(result, 2, obj);
+
+  return result;
+}
 
 WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
   ResourceMark rm(THREAD);
@@ -790,27 +857,93 @@
   ThreadToNativeFromVM ttn(thread);
   jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
   CHECK_JNI_EXCEPTION_(env, NULL);
-  result = env->NewObjectArray(3, clazz, NULL);
+  result = env->NewObjectArray(4, clazz, NULL);
   if (result == NULL) {
     return result;
   }
 
+  CodeBlobStub stub(code);
+  jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub);
+  env->SetObjectArrayElement(result, 0, codeBlob);
+
   jobject level = integerBox(thread, env, code->comp_level());
   CHECK_JNI_EXCEPTION_(env, NULL);
-  env->SetObjectArrayElement(result, 0, level);
+  env->SetObjectArrayElement(result, 1, level);
 
   jbyteArray insts = env->NewByteArray(insts_size);
   CHECK_JNI_EXCEPTION_(env, NULL);
   env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin());
-  env->SetObjectArrayElement(result, 1, insts);
+  env->SetObjectArrayElement(result, 2, insts);
 
   jobject id = integerBox(thread, env, code->compile_id());
   CHECK_JNI_EXCEPTION_(env, NULL);
-  env->SetObjectArrayElement(result, 2, id);
+  env->SetObjectArrayElement(result, 3, id);
 
   return result;
 WB_END
 
+CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
+  guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
+  BufferBlob* blob;
+  int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob));
+  if (full_size < size) {
+    full_size += round_to(size - full_size, oopSize);
+  }
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type);
+  }
+  // Track memory usage statistic after releasing CodeCache_lock
+  MemoryService::track_code_cache_memory_usage();
+  ::new (blob) BufferBlob("WB::DummyBlob", full_size);
+  return blob;
+}
+
+WB_ENTRY(jlong, WB_AllocateCodeBlob(JNIEnv* env, jobject o, jint size, jint blob_type))
+    return (jlong) WhiteBox::allocate_code_blob(size, blob_type);
+WB_END
+
+WB_ENTRY(void, WB_FreeCodeBlob(JNIEnv* env, jobject o, jlong addr))
+    BufferBlob::free((BufferBlob*) addr);
+WB_END
+
+WB_ENTRY(jobjectArray, WB_GetCodeHeapEntries(JNIEnv* env, jobject o, jint blob_type))
+  ResourceMark rm;
+  GrowableArray<CodeBlobStub*> blobs;
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    CodeHeap* heap = WhiteBox::get_code_heap(blob_type);
+    if (heap == NULL) {
+      return NULL;
+    }
+    for (CodeBlob* cb = (CodeBlob*) heap->first();
+         cb != NULL; cb = (CodeBlob*) heap->next(cb)) {
+      CodeBlobStub* stub = NEW_RESOURCE_OBJ(CodeBlobStub);
+      new (stub) CodeBlobStub(cb);
+      blobs.append(stub);
+    }
+  }
+  if (blobs.length() == 0) {
+    return NULL;
+  }
+  ThreadToNativeFromVM ttn(thread);
+  jobjectArray result = NULL;
+  jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
+  CHECK_JNI_EXCEPTION_(env, NULL);
+  result = env->NewObjectArray(blobs.length(), clazz, NULL);
+  if (result == NULL) {
+    return result;
+  }
+  int i = 0;
+  for (GrowableArrayIterator<CodeBlobStub*> it = blobs.begin();
+       it != blobs.end(); ++it) {
+    jobjectArray obj = codeBlob2objectArray(thread, env, *it);
+    env->SetObjectArrayElement(result, i, obj);
+    ++i;
+  }
+  return result;
+WB_END
+
 WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o))
   return (jlong) Thread::current()->stack_size();
 WB_END
@@ -1018,6 +1151,8 @@
       CC"(Ljava/lang/reflect/Executable;II)Z",        (void*)&WB_EnqueueMethodForCompilation},
   {CC"clearMethodState",
       CC"(Ljava/lang/reflect/Executable;)V",          (void*)&WB_ClearMethodState},
+  {CC"lockCompilation",    CC"()V",                   (void*)&WB_LockCompilation},
+  {CC"unlockCompilation",  CC"()V",                   (void*)&WB_UnlockCompilation},
   {CC"isConstantVMFlag",   CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag},
   {CC"isLockedVMFlag",     CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag},
   {CC"setBooleanVMFlag",   CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},
@@ -1055,6 +1190,10 @@
   {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"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 },
   {CC"getThreadStackSize", CC"()J",                   (void*)&WB_GetThreadStackSize },
   {CC"getThreadRemainingStackSize", CC"()J",          (void*)&WB_GetThreadRemainingStackSize },
 };
--- a/hotspot/src/share/vm/prims/whitebox.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -54,17 +54,24 @@
     }                                                                  \
   } while (0)
 
+class CodeBlob;
+class CodeHeap;
+
 class WhiteBox : public AllStatic {
  private:
   static bool _used;
  public:
+  static volatile bool compilation_locked;
   static bool used()     { return _used; }
   static void set_used() { _used = true; }
   static int offset_for_field(const char* field_name, oop object,
     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 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);
   static int array_bytes_to_length(size_t bytes);
   static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread,
     JNINativeMethod* method_array, int method_count);
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -317,8 +317,8 @@
  * c. 0 -> (3->2) -> 4.
  *    In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough
  *    to enable the profiling to fully occur at level 0. In this case we change the compilation level
- *    of the method to 2, because it'll allow it to run much faster without full profiling while c2
- *    is compiling.
+ *    of the method to 2 while the request is still in-queue, because it'll allow it to run much faster
+ *    without full profiling while c2 is compiling.
  *
  * d. 0 -> 3 -> 1 or 0 -> 2 -> 1.
  *    After a method was once compiled with C1 it can be identified as trivial and be compiled to
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp	Thu Nov 13 11:35:15 2014 -0500
@@ -87,6 +87,7 @@
 Mutex*   Compile_lock                 = NULL;
 Monitor* MethodCompileQueue_lock      = NULL;
 Monitor* CompileThread_lock           = NULL;
+Monitor* Compilation_lock             = NULL;
 Mutex*   CompileTaskAlloc_lock        = NULL;
 Mutex*   CompileStatistics_lock       = NULL;
 Mutex*   MultiArray_lock              = NULL;
@@ -274,7 +275,9 @@
   def(ProfileVM_lock               , Monitor, special,   false); // used for profiling of the VMThread
   def(CompileThread_lock           , Monitor, nonleaf+5,   false );
   def(PeriodicTask_lock            , Monitor, nonleaf+5,   true);
-
+  if (WhiteBoxAPI) {
+    def(Compilation_lock           , Monitor, leaf,        false );
+  }
 #ifdef INCLUDE_TRACE
   def(JfrMsg_lock                  , Monitor, leaf,        true);
   def(JfrBuffer_lock               , Mutex,   leaf,        true);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -90,6 +90,7 @@
 extern Mutex*   Compile_lock;                    // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
 extern Monitor* MethodCompileQueue_lock;         // a lock held when method compilations are enqueued, dequeued
 extern Monitor* CompileThread_lock;              // a lock held by compile threads during compilation system initialization
+extern Monitor* Compilation_lock;                // a lock used to pause compilation
 extern Mutex*   CompileTaskAlloc_lock;           // a lock held when CompileTasks are allocated
 extern Mutex*   CompileStatistics_lock;          // a lock held when updating compilation statistics
 extern Mutex*   MultiArray_lock;                 // a lock used to guard allocation of multi-dim arrays
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -54,13 +54,17 @@
 // Simple methods are as good being compiled with C1 as C2.
 // Determine if a given method is such a case.
 bool SimpleThresholdPolicy::is_trivial(Method* method) {
-  if (method->is_accessor()) return true;
-  if (method->code() != NULL) {
-    MethodData* mdo = method->method_data();
-    if (mdo != NULL && mdo->num_loops() == 0 &&
-        (method->code_size() < 5  || (mdo->num_blocks() < 4) && (method->code_size() < 15))) {
-      return !mdo->would_profile();
-    }
+  if (method->is_accessor() ||
+      method->is_constant_getter()) {
+    return true;
+  }
+  if (method->has_loops() || method->code_size() >= 15) {
+    return false;
+  }
+  MethodData* mdo = method->method_data();
+  if (mdo != NULL && !mdo->would_profile() &&
+      (method->code_size() < 5  || (mdo->num_blocks() < 4))) {
+    return true;
   }
   return false;
 }
--- a/hotspot/src/share/vm/runtime/sweeper.hpp	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/src/share/vm/runtime/sweeper.hpp	Thu Nov 13 11:35:15 2014 -0500
@@ -25,6 +25,8 @@
 #ifndef SHARE_VM_RUNTIME_SWEEPER_HPP
 #define SHARE_VM_RUNTIME_SWEEPER_HPP
 
+class WhiteBox;
+
 #include "utilities/ticks.hpp"
 // An NmethodSweeper is an incremental cleaner for:
 //    - cleanup inline caches
@@ -52,6 +54,8 @@
 //     nmethod's space is freed.
 
 class NMethodSweeper : public AllStatic {
+  friend class WhiteBox;
+ private:
   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
@@ -88,7 +92,6 @@
   static void handle_safepoint_request();
   static void do_stack_scanning();
   static void possibly_sweep();
-
  public:
   static long traversal_count()              { return _traversals; }
   static int  total_nof_methods_reclaimed()  { return _total_nof_methods_reclaimed; }
--- a/hotspot/test/TEST.groups	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/TEST.groups	Thu Nov 13 11:35:15 2014 -0500
@@ -426,7 +426,8 @@
   compiler/8005033/Test8005033.java \
   compiler/8005419/Test8005419.java \
   compiler/8005956/PolynomialRoot.java \
-  compiler/8007294/Test8007294.java
+  compiler/8007294/Test8007294.java \
+  compiler/EliminateAutoBox/UnsignedLoads.java
 
 hotspot_compiler_3 = \
   compiler/8007722/Test8007722.java \
--- a/hotspot/test/compiler/7068051/Test7068051.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/compiler/7068051/Test7068051.java	Thu Nov 13 11:35:15 2014 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,57 +26,116 @@
  * @test
  * @bug 7068051
  * @summary SIGSEGV in PhaseIdealLoop::build_loop_late_post on T5440
+ * @library /testlibrary
  *
- * @run shell/timeout=300 Test7068051.sh
+ * @run main/othervm -showversion -Xbatch Test7068051
  */
 
-import java.io.*;
-import java.nio.*;
-import java.util.*;
-import java.util.zip.*;
+import com.oracle.java.testlibrary.JDKToolLauncher;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 public class Test7068051 {
+    private static final String SELF_NAME = Test7068051.class.getSimpleName();
+    private static final String SELF_FILE_NAME = SELF_NAME + ".java";
+    private static final String JAR_NAME = "foo.jar";
+    private static final String TEST_PATH = System.getProperty("test.src");
+    private static final Path CURRENT_DIR = Paths.get(".");
+    private static final Path TEST_SOURCE_PATH = Paths.get(TEST_PATH, SELF_FILE_NAME);
 
-    public static void main (String[] args) throws Throwable {
+    public static void main (String[] args) throws IOException {
+        createTestJarFile();
+        System.out.println("Running test...");
 
-        ZipFile zf = new ZipFile(args[0]);
+        try (ZipFile zf = new ZipFile(JAR_NAME)) {
 
-        Enumeration<? extends ZipEntry> entries = zf.entries();
-        ArrayList<String> names = new ArrayList<String>();
-        while (entries.hasMoreElements()) {
-            names.add(entries.nextElement().getName());
-        }
+            Enumeration<? extends ZipEntry> entries = zf.entries();
+            ArrayList<String> names = new ArrayList<String>();
+            while (entries.hasMoreElements()) {
+                names.add(entries.nextElement().getName());
+            }
 
-        byte[] bytes = new byte[16];
-        for (String name : names) {
-            ZipEntry e = zf.getEntry(name);
+            byte[] bytes = new byte[16];
+            for (String name : names) {
+                ZipEntry e = zf.getEntry(name);
 
-            if (e.isDirectory())
-                continue;
+                if (e.isDirectory()) {
+                    continue;
+                }
 
-            final InputStream is = zf.getInputStream(e);
+                try (final InputStream is = zf.getInputStream(e)) {
+                    try {
+                        while (is.read(bytes) >= 0) {
+                        }
+                    } catch (IOException x) {
+                        System.out.println("..................................");
+                        System.out.println("          -->  is :" + is);
+                        System.out.println("          is.hash :" + is.hashCode());
+                        System.out.println();
+                        System.out.println("           e.name :" + e.getName());
+                        System.out.println("           e.hash :" + e.hashCode());
+                        System.out.println("         e.method :" + e.getMethod());
+                        System.out.println("           e.size :" + e.getSize());
+                        System.out.println("          e.csize :" + e.getCompressedSize());
+                        System.out.println("..................................");
 
-            try  {
-                while (is.read(bytes) >= 0) {
+                        throw new AssertionError("IOException was throwing while read the archive. Test failed.", x);
+                    }
                 }
-                is.close();
-
-            } catch (IOException x) {
-                 System.out.println("..................................");
-                 System.out.println("          -->  is :" + is);
-                 System.out.println("          is.hash :" + is.hashCode());
-                 System.out.println();
-                 System.out.println("           e.name :" + e.getName());
-                 System.out.println("           e.hash :" + e.hashCode());
-                 System.out.println("         e.method :" + e.getMethod());
-                 System.out.println("           e.size :" + e.getSize());
-                 System.out.println("          e.csize :" + e.getCompressedSize());
-
-                 x.printStackTrace();
-                 System.out.println("..................................");
-                 System.exit(97);
             }
         }
-        zf.close();
+        System.out.println("Test passed.");
+    }
+
+    private static void createTestJarFile() {
+        ArrayList<String> jarOptions = new ArrayList<>();
+
+        // jar cf foo.jar *
+        System.out.println("Creating jar file..");
+        jarOptions.add("cf");
+        jarOptions.add(JAR_NAME);
+        try {
+            for (int i = 0; i < 100; ++i) {
+                Path temp = Files.createTempFile(CURRENT_DIR, SELF_NAME, ".java");
+                Files.copy(TEST_SOURCE_PATH, temp, StandardCopyOption.REPLACE_EXISTING);
+                jarOptions.add(temp.toString());
+            }
+        } catch (IOException ex) {
+            throw new AssertionError("TESTBUG: Creating temp files failed.", ex);
+        }
+        runJar(jarOptions);
+
+        // jar -uf0 foo.jar Test7068051.java
+        System.out.println("Adding unpacked file...");
+        jarOptions.clear();
+        jarOptions.add("-uf0");
+        jarOptions.add(JAR_NAME);
+        jarOptions.add(TEST_SOURCE_PATH.toString());
+        runJar(jarOptions);
+    }
+
+    private static void runJar(List<String> params) {
+        JDKToolLauncher jar = JDKToolLauncher.create("jar");
+        for (String p : params) {
+            jar.addToolArg(p);
+        }
+        ProcessBuilder pb = new ProcessBuilder(jar.getCommand());
+        try {
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            output.shouldHaveExitValue(0);
+        } catch (IOException ex) {
+            throw new AssertionError("TESTBUG: jar failed.", ex);
+        }
     }
 }
--- a/hotspot/test/compiler/7068051/Test7068051.sh	Thu Nov 13 12:29:09 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-#!/bin/sh
-# 
-# Copyright (c) 2011, 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.
-# 
-# 
-## some tests require path to find test source dir
-if [ "${TESTSRC}" = "" ]
-then
-  TESTSRC=${PWD}
-  echo "TESTSRC not set.  Using "${TESTSRC}" as default"
-fi
-echo "TESTSRC=${TESTSRC}"
-## Adding common setup Variables for running shell tests.
-. ${TESTSRC}/../../test_env.sh
-
-set -x
-
-${COMPILEJAVA}/bin/jar xf ${COMPILEJAVA}/jre/lib/javaws.jar
-${COMPILEJAVA}/bin/jar cf foo.jar *
-cp ${TESTSRC}/Test7068051.java ./
-${COMPILEJAVA}/bin/jar -uf0 foo.jar Test7068051.java
-
-${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7068051.java
-
-${TESTJAVA}/bin/java ${TESTOPTS} -showversion -Xbatch Test7068051 foo.jar
-
--- a/hotspot/test/compiler/EliminateAutoBox/UnsignedLoads.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/compiler/EliminateAutoBox/UnsignedLoads.java	Thu Nov 13 11:35:15 2014 -0500
@@ -26,7 +26,7 @@
 /*
  * @test
  * @library /testlibrary
- * @run main/othervm -Xbatch -XX:+EliminateAutoBox
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
  *                   -XX:CompileOnly=::valueOf,::byteValue,::shortValue,::testUnsignedByte,::testUnsignedShort
  *                   UnsignedLoads
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java	Thu Nov 13 11:35:15 2014 -0500
@@ -0,0 +1,128 @@
+/*
+ * 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.management.MemoryPoolMXBean;
+import java.util.EnumSet;
+import java.util.ArrayList;
+
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.BlobType;
+import com.oracle.java.testlibrary.Asserts;
+
+/*
+ * @test AllocationCodeBlobTest
+ * @bug 8059624
+ * @library /testlibrary /testlibrary/whitebox
+ * @build AllocationCodeBlobTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
+ *                   -XX:-SegmentedCodeCache AllocationCodeBlobTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
+ *                   -XX:+SegmentedCodeCache AllocationCodeBlobTest
+ * @summary testing of WB::allocate/freeCodeBlob()
+ */
+public class AllocationCodeBlobTest {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final long CODE_CACHE_SIZE
+            = WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize");
+    private static final int SIZE = 1;
+
+    public static void main(String[] args) {
+        // check that Sweeper handels dummy blobs correctly
+        new ForcedSweeper(500).start();
+        EnumSet<BlobType> blobTypes = BlobType.getAvailable();
+        for (BlobType type : blobTypes) {
+            new AllocationCodeBlobTest(type).test();
+        }
+    }
+
+    private final BlobType type;
+    private final MemoryPoolMXBean bean;
+    private AllocationCodeBlobTest(BlobType type) {
+        this.type = type;
+        bean = type.getMemoryPool();
+    }
+
+    private void test() {
+        System.out.printf("type %s%n", type);
+        long start = getUsage();
+        long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
+        Asserts.assertNE(0, addr, "allocation failed");
+
+        long firstAllocation = getUsage();
+        Asserts.assertLTE(start + SIZE, firstAllocation,
+                "allocation should increase memory usage: "
+                + start + " + " + SIZE + " <= " + firstAllocation);
+
+        WHITE_BOX.freeCodeBlob(addr);
+        long firstFree = getUsage();
+        Asserts.assertLTE(firstFree, firstAllocation,
+                "free shouldn't increase memory usage: "
+                + firstFree + " <= " + firstAllocation);
+
+        addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
+        Asserts.assertNE(0, addr, "allocation failed");
+
+        long secondAllocation = getUsage();
+        Asserts.assertEQ(firstAllocation, secondAllocation);
+
+        WHITE_BOX.freeCodeBlob(addr);
+        System.out.println("allocating till possible...");
+        ArrayList<Long> blobs = new ArrayList<>();
+        int size = (int) (CODE_CACHE_SIZE >> 7);
+        while ((addr = WHITE_BOX.allocateCodeBlob(size, type.id)) != 0) {
+            blobs.add(addr);
+        }
+        for (Long blob : blobs) {
+            WHITE_BOX.freeCodeBlob(blob);
+        }
+    }
+
+    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/hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java	Thu Nov 13 11:35:15 2014 -0500
@@ -0,0 +1,95 @@
+/*
+ * 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.util.Arrays;
+import java.util.EnumSet;
+
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.CodeBlob;
+import sun.hotspot.code.BlobType;
+import com.oracle.java.testlibrary.Asserts;
+
+/*
+ * @test GetCodeHeapEntriesTest
+ * @bug 8059624
+ * @library /testlibrary /testlibrary/whitebox
+ * @build GetCodeHeapEntriesTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache
+ *                   GetCodeHeapEntriesTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache
+ *                   GetCodeHeapEntriesTest
+ * @summary testing of WB::getCodeHeapEntries()
+ */
+public class GetCodeHeapEntriesTest {
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final int SIZE = 1024;
+    private static final String DUMMY_NAME = "WB::DummyBlob";
+    private static EnumSet<BlobType> SEGMENTED_TYPES
+            = EnumSet.complementOf(EnumSet.of(BlobType.All));
+
+    public static void main(String[] args) {
+        EnumSet<BlobType> blobTypes = BlobType.getAvailable();
+        for (BlobType type : blobTypes) {
+            new GetCodeHeapEntriesTest(type).test();
+        }
+    }
+
+    private final BlobType type;
+    private GetCodeHeapEntriesTest(BlobType type) {
+        this.type = type;
+    }
+
+    private void test() {
+        System.out.printf("type %s%n", type);
+        long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
+        Asserts.assertNE(0, addr, "allocation failed");
+        CodeBlob[] blobs = CodeBlob.getCodeBlobs(type);
+        Asserts.assertNotNull(blobs);
+        CodeBlob blob = Arrays.stream(blobs)
+                              .filter(GetCodeHeapEntriesTest::filter)
+                              .findAny()
+                              .get();
+        Asserts.assertNotNull(blob);
+        Asserts.assertEQ(blob.code_blob_type, type);
+        Asserts.assertGTE(blob.size, SIZE);
+
+        WHITE_BOX.freeCodeBlob(addr);
+        blobs = CodeBlob.getCodeBlobs(type);
+        long count = Arrays.stream(blobs)
+                           .filter(GetCodeHeapEntriesTest::filter)
+                           .count();
+        Asserts.assertEQ(0L, count);
+    }
+
+    private static boolean filter(CodeBlob blob) {
+        if (blob == null) {
+            return false;
+        }
+        return DUMMY_NAME.equals(blob.name);
+    }
+}
--- a/hotspot/test/compiler/whitebox/GetNMethodTest.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java	Thu Nov 13 11:35:15 2014 -0500
@@ -22,7 +22,9 @@
  *
  */
 
+import sun.hotspot.code.BlobType;
 import sun.hotspot.code.NMethod;
+import com.oracle.java.testlibrary.Asserts;
 
 /*
  * @test GetNMethodTest
@@ -52,21 +54,46 @@
 
         compile();
         checkCompiled();
+
         NMethod nmethod = NMethod.get(method, testCase.isOsr());
         if (IS_VERBOSE) {
             System.out.println("nmethod = " + nmethod);
         }
-        if (nmethod == null) {
-            throw new RuntimeException("nmethod of compiled method is null");
+        Asserts.assertNotNull(nmethod,
+                "nmethod of compiled method is null");
+        Asserts.assertNotNull(nmethod.insts,
+                "nmethod.insts of compiled method is null");
+        Asserts.assertGT(nmethod.insts.length, 0,
+                "compiled method's instructions is empty");
+        Asserts.assertNotNull(nmethod.code_blob_type, "blob type is null");
+        if (WHITE_BOX.getBooleanVMFlag("SegmentedCodeCache")) {
+            Asserts.assertNE(nmethod.code_blob_type, BlobType.All);
+            switch (nmethod.comp_level) {
+            case 1:
+            case 4:
+                checkBlockType(nmethod, BlobType.MethodNonProfiled);
+                break;
+            case 2:
+            case 3:
+                checkBlockType(nmethod, BlobType.MethodNonProfiled);
+                break;
+            default:
+                throw new Error("unexpected comp level " + nmethod);
+            }
+        } else {
+            Asserts.assertEQ(nmethod.code_blob_type, BlobType.All);
         }
-        if (nmethod.insts.length == 0) {
-            throw new RuntimeException("compiled method's instructions is empty");
-        }
+
         deoptimize();
         checkNotCompiled();
         nmethod = NMethod.get(method, testCase.isOsr());
-        if (nmethod != null) {
-            throw new RuntimeException("nmethod of non-compiled method isn't null");
-        }
+        Asserts.assertNull(nmethod,
+                "nmethod of non-compiled method isn't null");
+    }
+
+    private void checkBlockType(NMethod nmethod, BlobType expectedType) {
+        Asserts.assertEQ(nmethod.code_blob_type, expectedType,
+                String.format("blob_type[%s] for %d level isn't %s",
+                        nmethod.code_blob_type, nmethod.comp_level, expectedType));
     }
 }
--- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java	Thu Nov 13 11:35:15 2014 -0500
@@ -29,7 +29,7 @@
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
- * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
+ * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
  * @summary testing of WB::isMethodCompilable()
  * @author igor.ignatyev@oracle.com
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/whitebox/LockCompilationTest.java	Thu Nov 13 11:35:15 2014 -0500
@@ -0,0 +1,91 @@
+/*
+ * 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 LockCompilationTest
+ * @bug 8059624
+ * @library /testlibrary /testlibrary/whitebox
+ * @build LockCompilationTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* LockCompilationTest
+ * @summary testing of WB::lock/unlockCompilation()
+ */
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+import com.oracle.java.testlibrary.Asserts;
+
+public class LockCompilationTest extends CompilerWhiteBoxTest {
+    public static void main(String[] args) throws Exception {
+        CompilerWhiteBoxTest.main(LockCompilationTest::new, args);
+    }
+
+    private LockCompilationTest(TestCase testCase) {
+        super(testCase);
+        // to prevent inlining of #method
+        WHITE_BOX.testSetDontInlineMethod(method, true);
+    }
+
+    protected void test() throws Exception {
+        checkNotCompiled();
+
+        System.out.println("locking compilation");
+        WHITE_BOX.lockCompilation();
+
+        try {
+            System.out.println("trying to compile");
+            compile();
+            // to check if it works correctly w/ safepoints
+            System.out.println("going to safepoint");
+            WHITE_BOX.fullGC();
+            waitBackgroundCompilation();
+            Asserts.assertTrue(
+                    WHITE_BOX.isMethodQueuedForCompilation(method),
+                    method + " must be in queue");
+            Asserts.assertFalse(
+                    WHITE_BOX.isMethodCompiled(method, false),
+                    method + " must be not compiled");
+            Asserts.assertEQ(
+                    WHITE_BOX.getMethodCompilationLevel(method, false), 0,
+                    method + " comp_level must be == 0");
+            Asserts.assertFalse(
+                    WHITE_BOX.isMethodCompiled(method, true),
+                    method + " must be not osr_compiled");
+            Asserts.assertEQ(
+                    WHITE_BOX.getMethodCompilationLevel(method, true), 0,
+                    method + " osr_comp_level must be == 0");
+        } finally {
+            System.out.println("unlocking compilation");
+            WHITE_BOX.unlockCompilation();
+        }
+        waitBackgroundCompilation();
+        Asserts.assertFalse(
+                WHITE_BOX.isMethodQueuedForCompilation(method),
+                method + " must not be in queue");
+    }
+}
+
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu Nov 13 11:35:15 2014 -0500
@@ -143,8 +143,14 @@
   }
   public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci);
   public native void    clearMethodState(Executable method);
+  public native void    lockCompilation();
+  public native void    unlockCompilation();
   public native int     getMethodEntryBci(Executable method);
   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 native Object[] getCodeHeapEntries(int type);
 
   // Intered strings
   public native boolean isInStringTable(String str);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/BlobType.java	Thu Nov 13 11:35:15 2014 -0500
@@ -0,0 +1,79 @@
+/*
+ * 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 sun.hotspot.code;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.EnumSet;
+
+import sun.hotspot.WhiteBox;
+
+public enum BlobType {
+    // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods)
+    MethodNonProfiled(0, "CodeHeap 'non-profiled nmethods'"),
+    // Execution level 2 and 3 (profiled) nmethods
+    MethodProfiled(1, "CodeHeap 'profiled nmethods'"),
+    // Non-nmethods like Buffers, Adapters and Runtime Stubs
+    NonNMethod(2, "CodeHeap 'non-nmethods'"),
+    // All types (No code cache segmentation)
+    All(3, "CodeCache");
+
+    public final int id;
+    private final String beanName;
+
+    private BlobType(int id, String beanName) {
+        this.id = id;
+        this.beanName = beanName;
+    }
+
+    public MemoryPoolMXBean getMemoryPool() {
+        for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) {
+            String name = bean.getName();
+            if (beanName.equals(name)) {
+                return bean;
+            }
+        }
+        return null;
+    }
+    public static EnumSet<BlobType> getAvailable() {
+        WhiteBox whiteBox = WhiteBox.getWhiteBox();
+        if (!whiteBox.getBooleanVMFlag("SegmentedCodeCache")) {
+            // only All for non segmented world
+            return EnumSet.of(All);
+        }
+        if (System.getProperty("java.vm.info").startsWith("interpreted ")) {
+            // only NonNMethod for -Xint
+            return EnumSet.of(NonNMethod);
+        }
+
+        EnumSet<BlobType> result = EnumSet.complementOf(EnumSet.of(All));
+        if (!whiteBox.getBooleanVMFlag("TieredCompilation")
+                || whiteBox.getIntxVMFlag("TieredStopAtLevel") <= 1) {
+            // there is no MethodProfiled in non tiered world or pure C1
+            result.remove(MethodProfiled);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/CodeBlob.java	Thu Nov 13 11:35:15 2014 -0500
@@ -0,0 +1,61 @@
+/*
+ * 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 sun.hotspot.code;
+
+import sun.hotspot.WhiteBox;
+
+public class CodeBlob {
+  private static final WhiteBox WB = WhiteBox.getWhiteBox();
+  public static CodeBlob[] getCodeBlobs(BlobType type) {
+    Object[] obj = WB.getCodeHeapEntries(type.id);
+    if (obj == null) {
+      return null;
+    }
+    CodeBlob[] result = new CodeBlob[obj.length];
+    for (int i = 0, n = result.length; i < n; ++i) {
+      result[i] = new CodeBlob((Object[]) obj[i]);
+    }
+    return result;
+  }
+  protected CodeBlob(Object[] obj) {
+    assert obj.length == 3;
+    name = (String) obj[0];
+    size = (Integer) obj[1];
+    code_blob_type = BlobType.values()[(Integer) obj[2]];
+    assert code_blob_type.id == (Integer) obj[2];
+  }
+  public final String name;
+  public final int size;
+  public final BlobType code_blob_type;
+
+  @Override
+  public String toString() {
+    return "CodeBlob{"
+        + "name=" + name
+        + ", size=" + size
+        + ", code_blob_type=" + code_blob_type
+        + '}';
+  }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java	Thu Nov 13 12:29:09 2014 +0100
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java	Thu Nov 13 11:35:15 2014 -0500
@@ -27,28 +27,30 @@
 import java.lang.reflect.Executable;
 import sun.hotspot.WhiteBox;
 
-public class NMethod {
+public class NMethod extends CodeBlob {
   private static final WhiteBox wb = WhiteBox.getWhiteBox();
   public static NMethod get(Executable method, boolean isOsr) {
     Object[] obj = wb.getNMethod(method, isOsr);
     return obj == null ? null : new NMethod(obj);
   }
   private NMethod(Object[] obj) {
-    assert obj.length == 3;
-    comp_level = (Integer) obj[0];
-    insts = (byte[]) obj[1];
-    compile_id = (Integer) obj[2];
+    super((Object[])obj[0]);
+    assert obj.length == 4;
+    comp_level = (Integer) obj[1];
+    insts = (byte[]) obj[2];
+    compile_id = (Integer) obj[3];
   }
-  public byte[] insts;
-  public int comp_level;
-  public int compile_id;
+  public final byte[] insts;
+  public final int comp_level;
+  public final int compile_id;
 
   @Override
   public String toString() {
-    return "NMethod{" +
-        "insts=" + insts +
-        ", comp_level=" + comp_level +
-        ", compile_id=" + compile_id +
-        '}';
+    return "NMethod{"
+        + super.toString()
+        + ", insts=" + insts
+        + ", comp_level=" + comp_level
+        + ", compile_id=" + compile_id
+        + '}';
   }
 }