changeset 43955:ba1071ebd14b

Merge
author jwilhelm
date Tue, 14 Feb 2017 01:32:38 +0100
parents 8124caee94a8 e7ebd1507bd7
children 3567eee750f2
files
diffstat 22 files changed, 765 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/elfmacros.h	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/elfmacros.h	Tue Feb 14 01:32:38 2017 +0100
@@ -33,6 +33,7 @@
 #define ELF_NHDR        Elf64_Nhdr
 #define ELF_DYN         Elf64_Dyn
 #define ELF_ADDR        Elf64_Addr
+#define ELF_AUXV        Elf64_auxv_t
 
 #define ELF_ST_TYPE     ELF64_ST_TYPE
 
@@ -45,6 +46,7 @@
 #define ELF_NHDR        Elf32_Nhdr
 #define ELF_DYN         Elf32_Dyn
 #define ELF_ADDR        Elf32_Addr
+#define ELF_AUXV        Elf32_auxv_t
 
 #define ELF_ST_TYPE     ELF32_ST_TYPE
 
--- a/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c	Tue Feb 14 01:32:38 2017 +0100
@@ -642,6 +642,18 @@
         if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) {
           return false;
         }
+      } else if (notep->n_type == NT_AUXV) {
+        // Get first segment from entry point
+        ELF_AUXV *auxv = (ELF_AUXV *)descdata;
+        while (auxv->a_type != AT_NULL) {
+          if (auxv->a_type == AT_ENTRY) {
+            // Set entry point address to address of dynamic section.
+            // We will adjust it in read_exec_segments().
+            ph->core->dynamic_addr = auxv->a_un.a_val;
+            break;
+          }
+          auxv++;
+        }
       }
       p = descdata + ROUNDUP(notep->n_descsz, 4);
    }
@@ -832,7 +844,13 @@
 
     // from PT_DYNAMIC we want to read address of first link_map addr
     case PT_DYNAMIC: {
-      ph->core->dynamic_addr = exec_php->p_vaddr;
+      if (exec_ehdr->e_type == ET_EXEC) {
+        ph->core->dynamic_addr = exec_php->p_vaddr;
+      } else { // ET_DYN
+        // dynamic_addr has entry point of executable.
+        // Thus we should substract it.
+        ph->core->dynamic_addr += exec_php->p_vaddr - exec_ehdr->e_entry;
+      }
       print_debug("address of _DYNAMIC is 0x%lx\n", ph->core->dynamic_addr);
       break;
     }
@@ -1030,8 +1048,9 @@
     goto err;
   }
 
-  if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) {
-    print_debug("executable file is not a valid ELF ET_EXEC file\n");
+  if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true ||
+      ((exec_ehdr.e_type != ET_EXEC) && (exec_ehdr.e_type != ET_DYN))) {
+    print_debug("executable file is not a valid ELF file\n");
     goto err;
   }
 
--- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -240,6 +240,11 @@
     assert(result == CodeHeap::contains(p), "");
     return result;
   }
+
+  bool contains_blob(const CodeBlob* blob) const {
+    return CodeHeap::contains(blob->code_begin());
+  }
+
   AOTCompiledMethod* find_aot(address p) const;
 
   virtual void* find_start(void* p)     const;
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -3995,10 +3995,14 @@
         ciMethod* target = type->as_ObjectType()->constant_value()->as_method_handle()->get_vmtarget();
         // We don't do CHA here so only inline static and statically bindable methods.
         if (target->is_static() || target->can_be_statically_bound()) {
-          Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
-          ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void());
-          if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
-            return true;
+          if (ciMethod::is_consistent_info(callee, target)) {
+            Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
+            ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void());
+            if (try_inline(target, /*holder_known*/ true, ignore_return, bc)) {
+              return true;
+            }
+          } else {
+            print_inlining(target, "signatures mismatch", /*success*/ false);
           }
         } else {
           print_inlining(target, "not static or statically bindable", /*success*/ false);
@@ -4026,6 +4030,8 @@
           if (try_method_handle_inline(target, ignore_return)) {
             return true;
           }
+        } else if (!ciMethod::is_consistent_info(callee, target)) {
+          print_inlining(target, "signatures mismatch", /*success*/ false);
         } else {
           ciSignature* signature = target->signature();
           const int receiver_skip = target->is_static() ? 0 : 1;
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -1409,6 +1409,97 @@
   }
 }
 
+// ------------------------------------------------------------------
+
+static BasicType erase_to_word_type(BasicType bt) {
+  if (is_subword_type(bt)) return T_INT;
+  if (bt == T_ARRAY)       return T_OBJECT;
+  return bt;
+}
+
+static bool basic_types_match(ciType* t1, ciType* t2) {
+  if (t1 == t2)  return true;
+  return erase_to_word_type(t1->basic_type()) == erase_to_word_type(t2->basic_type());
+}
+
+bool ciMethod::is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method) {
+  bool invoke_through_mh_intrinsic = declared_method->is_method_handle_intrinsic() &&
+                                  !resolved_method->is_method_handle_intrinsic();
+
+  if (!invoke_through_mh_intrinsic) {
+    // Method name & descriptor should stay the same.
+    // Signatures may reference unloaded types and thus they may be not strictly equal.
+    ciSymbol* declared_signature = declared_method->signature()->as_symbol();
+    ciSymbol* resolved_signature = resolved_method->signature()->as_symbol();
+
+    return (declared_method->name()->equals(resolved_method->name())) &&
+           (declared_signature->equals(resolved_signature));
+  }
+
+  ciMethod* linker = declared_method;
+  ciMethod* target = resolved_method;
+  // Linkers have appendix argument which is not passed to callee.
+  int has_appendix = MethodHandles::has_member_arg(linker->intrinsic_id()) ? 1 : 0;
+  if (linker->arg_size() != (target->arg_size() + has_appendix)) {
+    return false; // argument slot count mismatch
+  }
+
+  ciSignature* linker_sig = linker->signature();
+  ciSignature* target_sig = target->signature();
+
+  if (linker_sig->count() + (linker->is_static() ? 0 : 1) !=
+      target_sig->count() + (target->is_static() ? 0 : 1) + has_appendix) {
+    return false; // argument count mismatch
+  }
+
+  int sbase = 0, rbase = 0;
+  switch (linker->intrinsic_id()) {
+    case vmIntrinsics::_linkToVirtual:
+    case vmIntrinsics::_linkToInterface:
+    case vmIntrinsics::_linkToSpecial: {
+      if (target->is_static()) {
+        return false;
+      }
+      if (linker_sig->type_at(0)->is_primitive_type()) {
+        return false;  // receiver should be an oop
+      }
+      sbase = 1; // skip receiver
+      break;
+    }
+    case vmIntrinsics::_linkToStatic: {
+      if (!target->is_static()) {
+        return false;
+      }
+      break;
+    }
+    case vmIntrinsics::_invokeBasic: {
+      if (target->is_static()) {
+        if (target_sig->type_at(0)->is_primitive_type()) {
+          return false; // receiver should be an oop
+        }
+        rbase = 1; // skip receiver
+      }
+      break;
+    }
+  }
+  assert(target_sig->count() - rbase == linker_sig->count() - sbase - has_appendix, "argument count mismatch");
+  int arg_count = target_sig->count() - rbase;
+  for (int i = 0; i < arg_count; i++) {
+    if (!basic_types_match(linker_sig->type_at(sbase + i), target_sig->type_at(rbase + i))) {
+      return false;
+    }
+  }
+  // Only check the return type if the symbolic info has non-void return type.
+  // I.e. the return value of the resolved method can be dropped.
+  if (!linker->return_type()->is_void() &&
+      !basic_types_match(linker->return_type(), target->return_type())) {
+    return false;
+  }
+  return true; // no mismatch found
+}
+
+// ------------------------------------------------------------------
+
 #if INCLUDE_TRACE
 TraceStructCalleeMethod ciMethod::to_trace_struct() const {
   TraceStructCalleeMethod result;
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -353,6 +353,8 @@
   void print_name(outputStream* st = tty);
   void print_short_name(outputStream* st = tty);
 
+  static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
+
 #if INCLUDE_TRACE
   TraceStructCalleeMethod to_trace_struct() const;
 #endif
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -1152,21 +1152,26 @@
   Symbol* h_name = k->name();
   assert(class_name == NULL || class_name == h_name, "name mismatch");
 
-  bool define_succeeded = false;
   // Add class just loaded
   // If a class loader supports parallel classloading handle parallel define requests
   // find_or_define_instance_class may return a different InstanceKlass
   if (is_parallelCapable(class_loader)) {
-    instanceKlassHandle defined_k = find_or_define_instance_class(h_name, class_loader, k, CHECK_NULL);
-    if (k() == defined_k()) {
-      // we have won over other concurrent threads (if any) that are
-      // competing to define the same class.
-      define_succeeded = true;
+    instanceKlassHandle defined_k = find_or_define_instance_class(h_name, class_loader, k, THREAD);
+    if (!HAS_PENDING_EXCEPTION && defined_k() != k()) {
+      // If a parallel capable class loader already defined this class, register 'k' for cleanup.
+      assert(defined_k.not_null(), "Should have a klass if there's no exception");
+      loader_data->add_to_deallocate_list(k());
+      k = defined_k;
     }
-    k = defined_k;
   } else {
-    define_instance_class(k, CHECK_NULL);
-    define_succeeded = true;
+    define_instance_class(k, THREAD);
+  }
+
+  // If defining the class throws an exception register 'k' for cleanup.
+  if (HAS_PENDING_EXCEPTION) {
+    assert(k.not_null(), "Must have an instance klass here!");
+    loader_data->add_to_deallocate_list(k());
+    return NULL;
   }
 
   // Make sure we have an entry in the SystemDictionary on success
@@ -1518,8 +1523,16 @@
     // find_or_define_instance_class may return a different InstanceKlass
     if (!k.is_null()) {
       instanceKlassHandle defined_k =
-        find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh));
-      k = defined_k;
+        find_or_define_instance_class(class_name, class_loader, k, THREAD);
+      if (!HAS_PENDING_EXCEPTION && defined_k() != k()) {
+        // If a parallel capable class loader already defined this class, register 'k' for cleanup.
+        assert(defined_k.not_null(), "Should have a klass if there's no exception");
+        loader_data->add_to_deallocate_list(k());
+        k = defined_k;
+      } else if (HAS_PENDING_EXCEPTION) {
+        loader_data->add_to_deallocate_list(k());
+        return nh;
+      }
     }
     return k;
   } else {
--- a/hotspot/src/share/vm/code/codeCache.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -417,7 +417,7 @@
 CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) {
   assert(cb != NULL, "CodeBlob is null");
   FOR_ALL_HEAPS(heap) {
-    if ((*heap)->contains(cb->code_begin())) {
+    if ((*heap)->contains_blob(cb)) {
       return *heap;
     }
   }
--- a/hotspot/src/share/vm/code/codeCache.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/code/codeCache.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -304,11 +304,10 @@
     // If set to NULL, initialized by first call to next()
     _code_blob = (CodeBlob*)nm;
     if (nm != NULL) {
-      address start = nm->code_begin();
-      while(!(*_heap)->contains(start)) {
+      while(!(*_heap)->contains_blob(_code_blob)) {
         ++_heap;
       }
-      assert((*_heap)->contains(start), "match not found");
+      assert((*_heap)->contains_blob(_code_blob), "match not found");
     }
   }
 
--- a/hotspot/src/share/vm/memory/heap.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/memory/heap.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -190,6 +190,10 @@
   if (block != NULL) {
     assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
     assert(!block->free(), "must be marked free");
+    guarantee((char*) block >= _memory.low_boundary() && (char*) block < _memory.high(),
+              "The newly allocated block " INTPTR_FORMAT " is not within the heap "
+              "starting with "  INTPTR_FORMAT " and ending with "  INTPTR_FORMAT,
+              p2i(block), p2i(_memory.low_boundary()), p2i(_memory.high()));
     DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
     _max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
     _blob_count++;
@@ -204,6 +208,10 @@
     HeapBlock* b =  block_at(_next_segment);
     b->initialize(number_of_segments);
     _next_segment += number_of_segments;
+    guarantee((char*) b >= _memory.low_boundary() && (char*) block < _memory.high(),
+              "The newly allocated block " INTPTR_FORMAT " is not within the heap "
+              "starting with "  INTPTR_FORMAT " and ending with " INTPTR_FORMAT,
+              p2i(b), p2i(_memory.low_boundary()), p2i(_memory.high()));
     DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
     _max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity());
     _blob_count++;
@@ -219,6 +227,10 @@
   // Find start of HeapBlock
   HeapBlock* b = (((HeapBlock *)p) - 1);
   assert(b->allocated_space() == p, "sanity check");
+  guarantee((char*) b >= _memory.low_boundary() && (char*) b < _memory.high(),
+            "The block to be deallocated " INTPTR_FORMAT " is not within the heap "
+            "starting with "  INTPTR_FORMAT " and ending with " INTPTR_FORMAT,
+            p2i(b), p2i(_memory.low_boundary()), p2i(_memory.high()));
   DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapFreeVal,
              segments_to_size(b->length()) - sizeof(HeapBlock)));
   add_to_freelist(b);
--- a/hotspot/src/share/vm/memory/heap.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/memory/heap.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -153,7 +153,9 @@
   char* high() const                             { return _memory.high(); }
   char* high_boundary() const                    { return _memory.high_boundary(); }
 
-  virtual bool  contains(const void* p) const    { return low_boundary() <= p && p < high(); }
+  virtual bool contains(const void* p) const     { return low_boundary() <= p && p < high(); }
+  virtual bool contains_blob(const CodeBlob* blob) const { return low_boundary() <= (char*) blob && (char*) blob < high(); }
+
   virtual void* find_start(void* p)     const;   // returns the block containing p or NULL
   virtual CodeBlob* find_blob_unsafe(void* start) const;
   size_t alignment_unit()       const;           // alignment of any block
--- a/hotspot/src/share/vm/opto/callGenerator.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -46,7 +46,7 @@
   return TypeFunc::make(method());
 }
 
-bool CallGenerator::is_inlined_mh_linker(JVMState* jvms, ciMethod* callee) {
+bool CallGenerator::is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* callee) {
   ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
   return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic();
 }
@@ -142,7 +142,7 @@
   }
 
   CallStaticJavaNode *call = new CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci());
-  if (is_inlined_mh_linker(jvms, method())) {
+  if (is_inlined_method_handle_intrinsic(jvms, method())) {
     // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter,
     // additional information about the method being invoked should be attached
     // to the call site to make resolution logic work
@@ -241,7 +241,7 @@
   address target = SharedRuntime::get_resolve_virtual_call_stub();
   // Normal inline cache used for call
   CallDynamicJavaNode *call = new CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci());
-  if (is_inlined_mh_linker(jvms, method())) {
+  if (is_inlined_method_handle_intrinsic(jvms, method())) {
     // To be able to issue a direct call (optimized virtual or virtual)
     // and skip a call to MH.linkTo*/invokeBasic adapter, additional information
     // about the method being invoked should be attached to the call site to
@@ -785,8 +785,7 @@
 
 
 CallGenerator* CallGenerator::for_method_handle_call(JVMState* jvms, ciMethod* caller, ciMethod* callee, bool delayed_forbidden) {
-  assert(callee->is_method_handle_intrinsic() ||
-         callee->is_compiled_lambda_form(), "for_method_handle_call mismatch");
+  assert(callee->is_method_handle_intrinsic(), "for_method_handle_call mismatch");
   bool input_not_const;
   CallGenerator* cg = CallGenerator::for_method_handle_inline(jvms, caller, callee, input_not_const);
   Compile* C = Compile::current();
@@ -826,6 +825,13 @@
         const TypeOopPtr* oop_ptr = receiver->bottom_type()->is_oopptr();
         ciMethod* target = oop_ptr->const_oop()->as_method_handle()->get_vmtarget();
         const int vtable_index = Method::invalid_vtable_index;
+
+        if (!ciMethod::is_consistent_info(callee, target)) {
+          print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(),
+                                 "signatures mismatch");
+          return NULL;
+        }
+
         CallGenerator* cg = C->call_generator(target, vtable_index,
                                               false /* call_does_dispatch */,
                                               jvms,
@@ -833,9 +839,8 @@
                                               PROB_ALWAYS);
         return cg;
       } else {
-        const char* msg = "receiver not constant";
-        if (PrintInlining)  C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
-        C->log_inline_failure(msg);
+        print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(),
+                               "receiver not constant");
       }
     }
     break;
@@ -852,6 +857,12 @@
         const TypeOopPtr* oop_ptr = member_name->bottom_type()->is_oopptr();
         ciMethod* target = oop_ptr->const_oop()->as_member_name()->get_vmtarget();
 
+        if (!ciMethod::is_consistent_info(callee, target)) {
+          print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(),
+                                 "signatures mismatch");
+          return NULL;
+        }
+
         // In lambda forms we erase signature types to avoid resolving issues
         // involving class loaders.  When we optimize a method handle invoke
         // to a direct call we must cast the receiver and arguments to its
@@ -912,9 +923,8 @@
                                               speculative_receiver_type);
         return cg;
       } else {
-        const char* msg = "member_name not constant";
-        if (PrintInlining)  C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
-        C->log_inline_failure(msg);
+        print_inlining_failure(C, callee, jvms->depth() - 1, jvms->bci(),
+                               "member_name not constant");
       }
     }
     break;
--- a/hotspot/src/share/vm/opto/callGenerator.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/opto/callGenerator.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -170,7 +170,12 @@
     }
   }
 
-  static bool is_inlined_mh_linker(JVMState* jvms, ciMethod* m);
+  static void print_inlining_failure(Compile* C, ciMethod* callee, int inline_level, int bci, const char* msg) {
+    print_inlining(C, callee, inline_level, bci, msg);
+    C->log_inline_failure(msg);
+  }
+
+  static bool is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m);
 };
 
 
--- a/hotspot/src/share/vm/opto/doCall.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/opto/doCall.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -400,92 +400,10 @@
 }
 
 #ifdef ASSERT
-static bool check_type(ciType* t1, ciType* t2) {
-  // Either oop-oop or prim-prim pair.
-  if (t1->is_primitive_type() && t2->is_primitive_type()) {
-    return t1->size() == t2->size(); // argument sizes should match
-  } else {
-    return !t1->is_primitive_type() && !t2->is_primitive_type(); // oop-oop
-  }
-}
-
-static bool check_inlined_mh_linker_info(ciMethod* symbolic_info, ciMethod* resolved_method) {
-  assert(symbolic_info->is_method_handle_intrinsic(), "sanity");
-  assert(!resolved_method->is_method_handle_intrinsic(), "sanity");
-
-  if (!symbolic_info->is_loaded() || !resolved_method->is_loaded()) {
-    return true; // Don't compare unloaded methods.
-  }
-  // Linkers have appendix argument which is not passed to callee.
-  int has_appendix = MethodHandles::has_member_arg(symbolic_info->intrinsic_id()) ? 1 : 0;
-  if (symbolic_info->arg_size() != (resolved_method->arg_size() + has_appendix)) {
-    return false; // Total size of arguments on stack mismatch.
-  }
-  if (!symbolic_info->return_type()->is_void()) {
-    // Only check the return type if the symbolic method is not void
-    // i.e. the return value of the resolved method can be dropped
-    if (!check_type(symbolic_info->return_type(), resolved_method->return_type())) {
-      return false; // Return value size or type mismatch encountered.
-    }
-  }
-
-  switch (symbolic_info->intrinsic_id()) {
-    case vmIntrinsics::_linkToVirtual:
-    case vmIntrinsics::_linkToInterface:
-    case vmIntrinsics::_linkToSpecial: {
-      if (resolved_method->is_static())  return false;
-      break;
-    }
-    case vmIntrinsics::_linkToStatic: {
-      if (!resolved_method->is_static())  return false;
-      break;
-    }
-  }
-
-  ciSignature* symbolic_sig = symbolic_info->signature();
-  ciSignature* resolved_sig = resolved_method->signature();
-
-  if (symbolic_sig->count() + (symbolic_info->is_static() ? 0 : 1) !=
-      resolved_sig->count() + (resolved_method->is_static() ? 0 : 1) + has_appendix) {
-    return false; // Argument count mismatch
-  }
-
-  int sbase = 0, rbase = 0;
-  int arg_count = MIN2(symbolic_sig->count() - has_appendix, resolved_sig->count());
-  ciType* recv_type = NULL;
-  if (symbolic_info->is_static() && !resolved_method->is_static()) {
-    recv_type = symbolic_sig->type_at(0);
-    sbase = 1;
-  } else if (!symbolic_info->is_static() && resolved_method->is_static()) {
-    recv_type = resolved_sig->type_at(0);
-    rbase = 1;
-  }
-  if (recv_type != NULL && recv_type->is_primitive_type()) {
-    return false; // Receiver should be an oop.
-  }
-  for (int i = 0; i < arg_count; i++) {
-    if (!check_type(symbolic_sig->type_at(sbase + i), resolved_sig->type_at(rbase + i))) {
-      return false; // Argument size or type mismatch encountered.
-    }
-  }
-  return true;
-}
-
-static bool is_call_consistent_with_jvms(JVMState* jvms, CallGenerator* cg) {
+static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) {
   ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
   ciMethod* resolved_method = cg->method();
-
-  if (CallGenerator::is_inlined_mh_linker(jvms, resolved_method)) {
-    return check_inlined_mh_linker_info(symbolic_info, resolved_method);
-  } else {
-    // Method name & descriptor should stay the same.
-    return (symbolic_info->get_Method()->name() == resolved_method->get_Method()->name()) &&
-           (symbolic_info->get_Method()->signature() == resolved_method->get_Method()->signature());
-  }
-}
-
-static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) {
-  if (!is_call_consistent_with_jvms(jvms, cg)) {
+  if (!ciMethod::is_consistent_info(symbolic_info, resolved_method)) {
     tty->print_cr("JVMS:");
     jvms->dump();
     tty->print_cr("Bytecode info:");
--- a/hotspot/src/share/vm/prims/jvmti.xml	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/prims/jvmti.xml	Tue Feb 14 01:32:38 2017 +0100
@@ -1486,6 +1486,10 @@
       <description>
         Get the current thread.  
         The current thread is the Java programming language thread which has called the function.
+        The function may return <code>NULL</code> in the start phase if the
+        <internallink id="jvmtiCapabilities.can_generate_early_vmstart">
+        <code>can_generate_early_vmstart</code></internallink> capability is enabled
+        and the <code>java.lang.Thread</code> class has not been initialized yet.
         <p/>
         Note that most <jvmti/> functions that take a thread 
         as an argument will accept <code>NULL</code> to mean 
@@ -1498,7 +1502,7 @@
         <param id="thread_ptr">
 	  <outptr><jthread/></outptr>
 	  <description>
-	     On return, points to the current thread.
+	     On return, points to the current thread, or <code>NULL</code>.
 	  </description>
 	</param>
       </parameters>
@@ -14735,6 +14739,11 @@
       Clarified can_redefine_any_classes, can_retransform_any_classes and IsModifiableClass API to
       disallow some implementation defined classes.
   </change>
+  <change date="12 February 2017" version="9.0.0">
+      Minor update for GetCurrentThread function:
+       - The function may return NULL in the start phase if the
+         can_generate_early_vmstart capability is enabled.
+  </change>
 </changehistory>
 
 </specification>
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp	Tue Feb 14 01:32:38 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -51,6 +51,7 @@
 #include "services/serviceUtil.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
 #endif // INCLUDE_ALL_GCS
 
@@ -1534,6 +1535,14 @@
       if (_tags[i] == entry->tag()) {
         oop o = entry->object();
         assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
+#if INCLUDE_ALL_GCS
+        if (UseG1GC) {
+          // The reference in this tag map could be the only (implicitly weak)
+          // reference to that object. If we hand it out, we need to keep it live wrt
+          // SATB marking similar to other j.l.ref.Reference referents.
+          G1SATBCardTableModRefBS::enqueue(o);
+        }
+#endif
         jobject ref = JNIHandles::make_local(JavaThread::current(), o);
         _object_results->append(ref);
         _tag_results->append((uint64_t)entry->tag());
--- a/hotspot/src/share/vm/runtime/globals.hpp	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Tue Feb 14 01:32:38 2017 +0100
@@ -3374,7 +3374,7 @@
           "Code cache expansion size (in bytes)")                           \
           range(0, max_uintx)                                               \
                                                                             \
-  develop_pd(uintx, CodeCacheMinBlockLength,                                \
+  diagnostic_pd(uintx, CodeCacheMinBlockLength,                             \
           "Minimum number of segments in a code cache block")               \
           range(1, 100)                                                     \
                                                                             \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/stress/ReturnBlobToWrongHeapTest.java	Tue Feb 14 01:32:38 2017 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017, 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 ReturnBlobToWrongHeapTest
+ * @key stress
+ * @summary Test if VM attempts to return code blobs to an incorrect code heap or to outside of the code cache.
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI
+ *                   -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method
+ *                   -XX:+SegmentedCodeCache
+ *                   -XX:ReservedCodeCacheSize=16M
+ *                   -XX:CodeCacheMinBlockLength=1
+ *                   compiler.codecache.stress.ReturnBlobToWrongHeapTest
+ */
+
+package compiler.codecache.stress;
+
+import sun.hotspot.code.BlobType;
+
+import java.util.ArrayList;
+
+public class ReturnBlobToWrongHeapTest {
+    private static final long largeBlobSize = Helper.WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize") >> 6;
+    private static final long codeCacheMinBlockLength = Helper.WHITE_BOX.getUintxVMFlag("CodeCacheMinBlockLength");
+    private static final BlobType[] BLOB_TYPES = BlobType.getAvailable().toArray(new BlobType[0]);
+
+    // Allocate blob in first code heap (the code heap with index 0).
+    private static long allocate(int size) {
+        return Helper.WHITE_BOX.allocateCodeBlob(size, BLOB_TYPES[0].id);
+    }
+
+    // Free blob.
+    private static void free(long address) {
+        Helper.WHITE_BOX.freeCodeBlob(address);
+    }
+
+    public static void main(String[] args) {
+        if (codeCacheMinBlockLength == 1) {
+            // Fill first code heap with large blobs until allocation fails.
+            long address;
+            while ((address = allocate((int)largeBlobSize)) != 0) {
+            }
+
+            // Allocate segment-sized blocks in first code heap.
+            long lastSegmentSizedAddress = 0; // Address of the last segment-sized blob allocated
+            while ((address = allocate(0)) != 0) {
+                lastSegmentSizedAddress = address;
+            }
+
+            if (lastSegmentSizedAddress == 0) {
+                throw new RuntimeException("Test failed: Not possible to allocate segment-sized blob");
+            }
+
+            // Remove last segment-sized block from the first code heap.
+            free(lastSegmentSizedAddress);
+        } else {
+            throw new RuntimeException("Test requires CodeCacheMinBlockLength==1; CodeCacheMinBlockLength is " +
+                                       codeCacheMinBlockLength);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/InvokerSignatureMismatch.java	Tue Feb 14 01:32:38 2017 +0100
@@ -0,0 +1,56 @@
+package compiler.jsr292;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MethodHandleHelper;
+import jdk.internal.vm.annotation.ForceInline;
+
+/*
+ * @test
+ * @bug 8166110
+ * @library /test/lib / patches
+ * @modules java.base/jdk.internal.misc
+ *          java.base/jdk.internal.vm.annotation
+ *
+ * @build java.base/java.lang.invoke.MethodHandleHelper
+ * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:-TieredCompilation
+ *                                 compiler.jsr292.InvokerSignatureMismatch
+ */
+public class InvokerSignatureMismatch {
+
+    static final MethodHandle INT_MH;
+
+    static {
+        MethodHandle mhI = null;
+        try {
+           mhI = MethodHandles.lookup().findStatic(InvokerSignatureMismatch.class, "bodyI", MethodType.methodType(void.class, int.class));
+        } catch (Throwable e) {
+        }
+        INT_MH = mhI;
+    }
+
+    public static void main(String[] args) throws Throwable {
+        for (int i = 0; i < 50_000; i++) { // OSR
+            mainLink(i);
+            mainInvoke(i);
+        }
+    }
+
+    static void mainLink(int i) throws Throwable {
+        Object name = MethodHandleHelper.internalMemberName(INT_MH);
+        MethodHandleHelper.linkToStatic(INT_MH, (float) i, name);
+    }
+
+    static void mainInvoke(int i) throws Throwable {
+        MethodHandleHelper.invokeBasicV(INT_MH, (float) i);
+    }
+
+    static int cnt = 0;
+    static void bodyI(int x) {
+        if ((x & 1023) == 0) { // already optimized x % 1024 == 0
+            ++cnt;
+        }
+    }
+
+}
--- a/hotspot/test/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/test/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java	Tue Feb 14 01:32:38 2017 +0100
@@ -44,6 +44,21 @@
     }
 
     @ForceInline
+    public static Object internalMemberName(MethodHandle mh) throws Throwable {
+        return mh.internalMemberName();
+    }
+
+    @ForceInline
+    public static void linkToStatic(MethodHandle mh, float arg, Object name) throws Throwable {
+        MethodHandle.linkToStatic(mh, arg, name);
+    }
+
+    @ForceInline
+    public static void invokeBasicV(MethodHandle mh, float arg) throws Throwable {
+        mh.invokeBasic(arg);
+    }
+
+    @ForceInline
     public static Object invokeBasicL(MethodHandle mh) throws Throwable {
         return mh.invokeBasic();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Metaspace/DefineClass.java	Tue Feb 14 01:32:38 2017 +0100
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017 SAP SE. 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 8173743
+ * @summary Failures during class definition can lead to memory leaks in metaspace
+ * @library /test/lib
+ * @run main/othervm test.DefineClass defineClass
+ * @run main/othervm test.DefineClass defineSystemClass
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions
+                     -XX:+UnsyncloadClass -XX:+AllowParallelDefineClass
+                     test.DefineClass defineClassParallel
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions
+                     -XX:+UnsyncloadClass -XX:-AllowParallelDefineClass
+                     test.DefineClass defineClassParallel
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions
+                     -XX:-UnsyncloadClass -XX:+AllowParallelDefineClass
+                     test.DefineClass defineClassParallel
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions
+                     -XX:-UnsyncloadClass -XX:-AllowParallelDefineClass
+                     test.DefineClass defineClassParallel
+ * @run main/othervm test.DefineClass redefineClass
+ * @run main/othervm test.DefineClass redefineClassWithError
+ * @author volker.simonis@gmail.com
+ */
+
+package test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+import java.lang.management.ManagementFactory;
+import java.util.Scanner;
+import java.util.concurrent.CountDownLatch;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import com.sun.tools.attach.VirtualMachine;
+
+import jdk.test.lib.process.ProcessTools;
+
+public class DefineClass {
+
+    private static Instrumentation instrumentation;
+
+    public void getID(CountDownLatch start, CountDownLatch stop) {
+        String id = "AAAAAAAA";
+        System.out.println(id);
+        try {
+            // Signal that we've entered the activation..
+            start.countDown();
+            //..and wait until we can leave it.
+            stop.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        System.out.println(id);
+        return;
+    }
+
+    private static class MyThread extends Thread {
+        private DefineClass dc;
+        private CountDownLatch start, stop;
+
+        public MyThread(DefineClass dc, CountDownLatch start, CountDownLatch stop) {
+            this.dc = dc;
+            this.start = start;
+            this.stop = stop;
+        }
+
+        public void run() {
+            dc.getID(start, stop);
+        }
+    }
+
+    private static class ParallelLoadingThread extends Thread {
+        private MyParallelClassLoader pcl;
+        private CountDownLatch stop;
+        private byte[] buf;
+
+        public ParallelLoadingThread(MyParallelClassLoader pcl, byte[] buf, CountDownLatch stop) {
+            this.pcl = pcl;
+            this.stop = stop;
+            this.buf = buf;
+        }
+
+        public void run() {
+            try {
+                stop.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            try {
+                @SuppressWarnings("unchecked")
+                Class<DefineClass> dc = (Class<DefineClass>) pcl.myDefineClass(DefineClass.class.getName(), buf, 0, buf.length);
+            }
+            catch (LinkageError jle) {
+                // Expected with a parallel capable class loader and
+                // -XX:+UnsyncloadClass or -XX:+AllowParallelDefineClass
+                pcl.incrementLinkageErrors();
+            }
+
+        }
+    }
+
+    static private class MyClassLoader extends ClassLoader {
+        public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
+            return defineClass(name, b, off, len, null);
+        }
+    }
+
+    static private class MyParallelClassLoader extends ClassLoader {
+        static {
+            System.out.println("parallelCapable : " + registerAsParallelCapable());
+        }
+        public Class<?> myDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError {
+            return defineClass(name, b, off, len, null);
+        }
+        public synchronized void incrementLinkageErrors() {
+            linkageErrors++;
+        }
+        public int getLinkageErrors() {
+            return linkageErrors;
+        }
+        private volatile int linkageErrors;
+    }
+
+    public static void agentmain(String args, Instrumentation inst) {
+        System.out.println("Loading Java Agent.");
+        instrumentation = inst;
+    }
+
+
+    private static void loadInstrumentationAgent(String myName, byte[] buf) throws Exception {
+        // Create agent jar file on the fly
+        Manifest m = new Manifest();
+        m.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        m.getMainAttributes().put(new Attributes.Name("Agent-Class"), myName);
+        m.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
+        File jarFile = File.createTempFile("agent", ".jar");
+        jarFile.deleteOnExit();
+        JarOutputStream jar = new JarOutputStream(new FileOutputStream(jarFile), m);
+        jar.putNextEntry(new JarEntry(myName.replace('.', '/') + ".class"));
+        jar.write(buf);
+        jar.close();
+        String pid = Long.toString(ProcessTools.getProcessId());
+        System.out.println("Our pid is = " + pid);
+        VirtualMachine vm = VirtualMachine.attach(pid);
+        vm.loadAgent(jarFile.getAbsolutePath());
+    }
+
+    private static byte[] getBytecodes(String myName) throws Exception {
+        InputStream is = DefineClass.class.getResourceAsStream(myName + ".class");
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buf = new byte[4096];
+        int len;
+        while ((len = is.read(buf)) != -1) baos.write(buf, 0, len);
+        buf = baos.toByteArray();
+        System.out.println("sizeof(" + myName + ".class) == " + buf.length);
+        return buf;
+    }
+
+    private static int getStringIndex(String needle, byte[] buf) {
+        return getStringIndex(needle, buf, 0);
+    }
+
+    private static int getStringIndex(String needle, byte[] buf, int offset) {
+        outer:
+        for (int i = offset; i < buf.length - offset - needle.length(); i++) {
+            for (int j = 0; j < needle.length(); j++) {
+                if (buf[i + j] != (byte)needle.charAt(j)) continue outer;
+            }
+            return i;
+        }
+        return 0;
+    }
+
+    private static void replaceString(byte[] buf, String name, int index) {
+        for (int i = index; i < index + name.length(); i++) {
+            buf[i] = (byte)name.charAt(i - index);
+        }
+    }
+
+    private static MBeanServer mbserver = ManagementFactory.getPlatformMBeanServer();
+
+    private static int getClassStats(String pattern) {
+        try {
+            ObjectName diagCmd = new ObjectName("com.sun.management:type=DiagnosticCommand");
+
+            String result = (String)mbserver.invoke(diagCmd , "gcClassStats" , new Object[] { null }, new String[] {String[].class.getName()});
+            int count = 0;
+            try (Scanner s = new Scanner(result)) {
+                if (s.hasNextLine()) {
+                    System.out.println(s.nextLine());
+                }
+                while (s.hasNextLine()) {
+                    String l = s.nextLine();
+                    if (l.endsWith(pattern)) {
+                        count++;
+                        System.out.println(l);
+                    }
+                }
+            }
+            return count;
+        }
+        catch (Exception e) {
+            throw new RuntimeException("Test failed because we can't read the class statistics!", e);
+        }
+    }
+
+    private static void printClassStats(int expectedCount, boolean reportError) {
+        int count = getClassStats("DefineClass");
+        String res = "Should have " + expectedCount +
+                     " DefineClass instances and we have: " + count;
+        System.out.println(res);
+        if (reportError && count != expectedCount) {
+            throw new RuntimeException(res);
+        }
+    }
+
+    public static final int ITERATIONS = 10;
+
+    public static void main(String[] args) throws Exception {
+        String myName = DefineClass.class.getName();
+        byte[] buf = getBytecodes(myName.substring(myName.lastIndexOf(".") + 1));
+        int iterations = (args.length > 1 ? Integer.parseInt(args[1]) : ITERATIONS);
+
+        if (args.length == 0 || "defineClass".equals(args[0])) {
+            MyClassLoader cl = new MyClassLoader();
+            for (int i = 0; i < iterations; i++) {
+                try {
+                    @SuppressWarnings("unchecked")
+                    Class<DefineClass> dc = (Class<DefineClass>) cl.myDefineClass(myName, buf, 0, buf.length);
+                    System.out.println(dc);
+                }
+                catch (LinkageError jle) {
+                    // Can only define once!
+                    if (i == 0) throw new Exception("Should succeed the first time.");
+                }
+            }
+            // We expect to have two instances of DefineClass here: the initial version in which we are
+            // executing and another version which was loaded into our own classloader 'MyClassLoader'.
+            // All the subsequent attempts to reload DefineClass into our 'MyClassLoader' should have failed.
+            printClassStats(2, false);
+            System.gc();
+            System.out.println("System.gc()");
+            // At least after System.gc() the failed loading attempts should leave no instances around!
+            printClassStats(2, true);
+        }
+        else if ("defineSystemClass".equals(args[0])) {
+            MyClassLoader cl = new MyClassLoader();
+            int index = getStringIndex("test/DefineClass", buf);
+            replaceString(buf, "java/DefineClass", index);
+            while ((index = getStringIndex("Ltest/DefineClass;", buf, index + 1)) != 0) {
+                replaceString(buf, "Ljava/DefineClass;", index);
+            }
+            index = getStringIndex("test.DefineClass", buf);
+            replaceString(buf, "java.DefineClass", index);
+
+            for (int i = 0; i < iterations; i++) {
+                try {
+                    @SuppressWarnings("unchecked")
+                    Class<DefineClass> dc = (Class<DefineClass>) cl.myDefineClass(null, buf, 0, buf.length);
+                    throw new RuntimeException("Defining a class in the 'java' package should fail!");
+                }
+                catch (java.lang.SecurityException jlse) {
+                    // Expected, because we're not allowed to define a class in the 'java' package
+                }
+            }
+            // We expect to stay with one (the initial) instances of DefineClass.
+            // All the subsequent attempts to reload DefineClass into the 'java' package should have failed.
+            printClassStats(1, false);
+            System.gc();
+            System.out.println("System.gc()");
+            // At least after System.gc() the failed loading attempts should leave no instances around!
+            printClassStats(1, true);
+        }
+        else if ("defineClassParallel".equals(args[0])) {
+            MyParallelClassLoader pcl = new MyParallelClassLoader();
+            CountDownLatch stop = new CountDownLatch(1);
+
+            Thread[] threads = new Thread[iterations];
+            for (int i = 0; i < iterations; i++) {
+                (threads[i] = new ParallelLoadingThread(pcl, buf, stop)).start();
+            }
+            stop.countDown(); // start parallel class loading..
+            // ..and wait until all threads loaded the class
+            for (int i = 0; i < iterations; i++) {
+                threads[i].join();
+            }
+            System.out.print("Counted " + pcl.getLinkageErrors() + " LinkageErrors ");
+            System.out.println(pcl.getLinkageErrors() == 0 ?
+                    "" : "(use -XX:+UnsyncloadClass and/or -XX:+AllowParallelDefineClass to avoid this)");
+            System.gc();
+            System.out.println("System.gc()");
+            // After System.gc() we expect to remain with two instances: one is the initial version which is
+            // kept alive by this main method and another one in the parallel class loader.
+            printClassStats(2, true);
+        }
+        else if ("redefineClass".equals(args[0])) {
+            loadInstrumentationAgent(myName, buf);
+            int index = getStringIndex("AAAAAAAA", buf);
+            CountDownLatch stop = new CountDownLatch(1);
+
+            Thread[] threads = new Thread[iterations];
+            for (int i = 0; i < iterations; i++) {
+                buf[index] = (byte) ('A' + i + 1); // Change string constant in getID() which is legal in redefinition
+                instrumentation.redefineClasses(new ClassDefinition(DefineClass.class, buf));
+                DefineClass dc = DefineClass.class.newInstance();
+                CountDownLatch start = new CountDownLatch(1);
+                (threads[i] = new MyThread(dc, start, stop)).start();
+                start.await(); // Wait until the new thread entered the getID() method
+            }
+            // We expect to have one instance for each redefinition because they are all kept alive by an activation
+            // plus the initial version which is kept active by this main method.
+            printClassStats(iterations + 1, false);
+            stop.countDown(); // Let all threads leave the DefineClass.getID() activation..
+            // ..and wait until really all of them returned from DefineClass.getID()
+            for (int i = 0; i < iterations; i++) {
+                threads[i].join();
+            }
+            System.gc();
+            System.out.println("System.gc()");
+            // After System.gc() we expect to remain with two instances: one is the initial version which is
+            // kept alive by this main method and another one which is the latest redefined version.
+            printClassStats(2, true);
+        }
+        else if ("redefineClassWithError".equals(args[0])) {
+            loadInstrumentationAgent(myName, buf);
+            int index = getStringIndex("getID", buf);
+
+            for (int i = 0; i < iterations; i++) {
+                buf[index] = (byte) 'X'; // Change getID() to XetID() which is illegal in redefinition
+                try {
+                    instrumentation.redefineClasses(new ClassDefinition(DefineClass.class, buf));
+                    throw new RuntimeException("Class redefinition isn't allowed to change method names!");
+                }
+                catch (UnsupportedOperationException uoe) {
+                    // Expected because redefinition can't change the name of methods
+                }
+            }
+            // We expect just a single DefineClass instance because failed redefinitions should
+            // leave no garbage around.
+            printClassStats(1, false);
+            System.gc();
+            System.out.println("System.gc()");
+            // At least after a System.gc() we should definitely stay with a single instance!
+            printClassStats(1, true);
+        }
+    }
+}
--- a/hotspot/test/serviceability/sa/TestCpoolForInvokeDynamic.java	Sun Feb 12 04:49:38 2017 +0100
+++ b/hotspot/test/serviceability/sa/TestCpoolForInvokeDynamic.java	Tue Feb 14 01:32:38 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -51,7 +51,6 @@
  *          jdk.hotspot.agent/sun.jvm.hotspot.oops
  *          jdk.hotspot.agent/sun.jvm.hotspot.debugger
  *          jdk.hotspot.agent/sun.jvm.hotspot.ui.classbrowser
- * @ignore 8169232
  * @run main/othervm TestCpoolForInvokeDynamic
  */