changeset 6262:0ab097f7ee3f

Merge
author ehelin
date Fri, 11 Apr 2014 10:31:25 +0200
parents fcb88e54b943 192d9ccbbdfb
children b6c7cffc044b
files
diffstat 23 files changed, 457 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -958,7 +958,7 @@
 
   // reset handle block
   __ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), G3_scratch);
-  __ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
+  __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
 
 
   // handle exceptions (exception handling will handle unlocking!)
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -2687,7 +2687,7 @@
   if (!is_critical_native) {
     // reset handle block
     __ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5);
-    __ st_ptr(G0, L5, JNIHandleBlock::top_offset_in_bytes());
+    __ st(G0, L5, JNIHandleBlock::top_offset_in_bytes());
 
     __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch);
     check_forward_pending_exception(masm, G3_scratch);
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1147,7 +1147,7 @@
 
   // reset handle block
   __ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
-  __ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
+  __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
 
   // If we have an oop result store it where it will be safe for any further gc
   // until we return now that we've released the handle it might be protected by
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1358,7 +1358,7 @@
 
   // reset handle block
   __ movptr(t, Address(thread, JavaThread::active_handles_offset()));
-  __ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
+  __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
 
   // If result was an oop then unbox and save it in the frame
   { Label L;
--- a/src/cpu/x86/vm/globals_x86.hpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/globals_x86.hpp	Fri Apr 11 10:31:25 2014 +0200
@@ -162,7 +162,7 @@
           "Number of milliseconds to wait before start calculating aborts " \
           "for RTM locking")                                                \
                                                                             \
-  experimental(bool, UseRTMXendForLockBusy, false,                          \
+  experimental(bool, UseRTMXendForLockBusy, true,                           \
           "Use RTM Xend instead of Xabort when lock busy")                  \
                                                                             \
   /* assembler */                                                           \
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1488,11 +1488,10 @@
     movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort
     bind(L_rtm_retry);
   }
-  if (!UseRTMXendForLockBusy) {
-    movptr(tmpReg, Address(objReg, 0));
-    testptr(tmpReg, markOopDesc::monitor_value);  // inflated vs stack-locked|neutral|biased
-    jcc(Assembler::notZero, IsInflated);
-  }
+  movptr(tmpReg, Address(objReg, 0));
+  testptr(tmpReg, markOopDesc::monitor_value);  // inflated vs stack-locked|neutral|biased
+  jcc(Assembler::notZero, IsInflated);
+
   if (PrintPreciseRTMLockingStatistics || profile_rtm) {
     Label L_noincrement;
     if (RTMTotalCountIncrRate > 1) {
@@ -1512,10 +1511,7 @@
   Register abort_status_Reg = tmpReg; // status of abort is stored in RAX
   if (UseRTMXendForLockBusy) {
     xend();
-    movptr(tmpReg, Address(objReg, 0));
-    testptr(tmpReg, markOopDesc::monitor_value);  // inflated vs stack-locked|neutral|biased
-    jcc(Assembler::notZero, IsInflated);
-    movptr(abort_status_Reg, 0x1);                // Set the abort status to 1 (as xabort does)
+    movptr(abort_status_Reg, 0x2);   // Set the abort status to 2 (so we can retry)
     jmp(L_decrement_retry);
   }
   else {
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -2266,7 +2266,7 @@
   if (!is_critical_native) {
     // reset handle block
     __ movptr(rcx, Address(thread, JavaThread::active_handles_offset()));
-    __ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
+    __ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
 
     // Any exception pending?
     __ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD);
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -2509,7 +2509,7 @@
   if (!is_critical_native) {
     // reset handle block
     __ movptr(rcx, Address(r15_thread, JavaThread::active_handles_offset()));
-    __ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
+    __ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
   }
 
   // pop our frame
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1287,7 +1287,7 @@
 
   // reset handle block
   __ movptr(t, Address(thread, JavaThread::active_handles_offset()));
-  __ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
+  __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
 
   // If result was an oop then unbox and save it in the frame
   { Label L;
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1259,7 +1259,7 @@
 
   // reset handle block
   __ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
-  __ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
+  __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
 
   // If result is an oop unbox and store it in frame where gc will see it
   // and result handler will pick it up
--- a/src/share/vm/oops/instanceKlass.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/oops/instanceKlass.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -3409,6 +3409,10 @@
               ("purge: %s(%s): prev method @%d in version @%d is alive",
               method->name()->as_C_string(),
               method->signature()->as_C_string(), j, i));
+            if (method->method_data() != NULL) {
+              // Clean out any weak method links
+              method->method_data()->clean_weak_method_links();
+            }
           }
         }
       }
@@ -3418,6 +3422,14 @@
       ("purge: previous version stats: live=%d, deleted=%d", live_count,
       deleted_count));
   }
+
+  Array<Method*>* methods = ik->methods();
+  int num_methods = methods->length();
+  for (int index2 = 0; index2 < num_methods; ++index2) {
+    if (methods->at(index2)->method_data() != NULL) {
+      methods->at(index2)->method_data()->clean_weak_method_links();
+    }
+  }
 }
 
 // External interface for use during class unloading.
--- a/src/share/vm/oops/methodData.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/oops/methodData.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1531,9 +1531,35 @@
   }
 }
 
-// Remove SpeculativeTrapData entries that reference an unloaded
-// method
-void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
+class CleanExtraDataClosure : public StackObj {
+public:
+  virtual bool is_live(Method* m) = 0;
+};
+
+// Check for entries that reference an unloaded method
+class CleanExtraDataKlassClosure : public CleanExtraDataClosure {
+private:
+  BoolObjectClosure* _is_alive;
+public:
+  CleanExtraDataKlassClosure(BoolObjectClosure* is_alive) : _is_alive(is_alive) {}
+  bool is_live(Method* m) {
+    return m->method_holder()->is_loader_alive(_is_alive);
+  }
+};
+
+// Check for entries that reference a redefined method
+class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
+public:
+  CleanExtraDataMethodClosure() {}
+  bool is_live(Method* m) {
+    return m->on_stack();
+  }
+};
+
+
+// Remove SpeculativeTrapData entries that reference an unloaded or
+// redefined method
+void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
   DataLayout* dp  = extra_data_base();
   DataLayout* end = extra_data_limit();
 
@@ -1544,7 +1570,7 @@
       SpeculativeTrapData* data = new SpeculativeTrapData(dp);
       Method* m = data->method();
       assert(m != NULL, "should have a method");
-      if (!m->method_holder()->is_loader_alive(is_alive)) {
+      if (!cl->is_live(m)) {
         // "shift" accumulates the number of cells for dead
         // SpeculativeTrapData entries that have been seen so
         // far. Following entries must be shifted left by that many
@@ -1575,9 +1601,9 @@
   }
 }
 
-// Verify there's no unloaded method referenced by a
+// Verify there's no unloaded or redefined method referenced by a
 // SpeculativeTrapData entry
-void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
+void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
 #ifdef ASSERT
   DataLayout* dp  = extra_data_base();
   DataLayout* end = extra_data_limit();
@@ -1587,7 +1613,7 @@
     case DataLayout::speculative_trap_data_tag: {
       SpeculativeTrapData* data = new SpeculativeTrapData(dp);
       Method* m = data->method();
-      assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist");
+      assert(m != NULL && cl->is_live(m), "Method should exist");
       break;
     }
     case DataLayout::bit_data_tag:
@@ -1613,6 +1639,19 @@
     parameters->clean_weak_klass_links(is_alive);
   }
 
-  clean_extra_data(is_alive);
-  verify_extra_data_clean(is_alive);
+  CleanExtraDataKlassClosure cl(is_alive);
+  clean_extra_data(&cl);
+  verify_extra_data_clean(&cl);
 }
+
+void MethodData::clean_weak_method_links() {
+  for (ProfileData* data = first_data();
+       is_valid(data);
+       data = next_data(data)) {
+    data->clean_weak_method_links();
+  }
+
+  CleanExtraDataMethodClosure cl;
+  clean_extra_data(&cl);
+  verify_extra_data_clean(&cl);
+}
--- a/src/share/vm/oops/methodData.hpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/oops/methodData.hpp	Fri Apr 11 10:31:25 2014 +0200
@@ -251,6 +251,9 @@
 
   // GC support
   void clean_weak_klass_links(BoolObjectClosure* cl);
+
+  // Redefinition support
+  void clean_weak_method_links();
 };
 
 
@@ -506,6 +509,9 @@
   // GC support
   virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
 
+  // Redefinition support
+  virtual void clean_weak_method_links() {}
+
   // CI translation: ProfileData can represent both MethodDataOop data
   // as well as CIMethodData data. This function is provided for translating
   // an oop in a ProfileData to the ci equivalent. Generally speaking,
@@ -1989,6 +1995,7 @@
 //
 
 CC_INTERP_ONLY(class BytecodeInterpreter;)
+class CleanExtraDataClosure;
 
 class MethodData : public Metadata {
   friend class VMStructs;
@@ -2146,9 +2153,9 @@
   static bool profile_parameters_jsr292_only();
   static bool profile_all_parameters();
 
-  void clean_extra_data(BoolObjectClosure* is_alive);
+  void clean_extra_data(CleanExtraDataClosure* cl);
   void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
-  void verify_extra_data_clean(BoolObjectClosure* is_alive);
+  void verify_extra_data_clean(CleanExtraDataClosure* cl);
 
 public:
   static int header_size() {
@@ -2440,6 +2447,8 @@
   static bool profile_return_jsr292_only();
 
   void clean_method_data(BoolObjectClosure* is_alive);
+
+  void clean_weak_method_links();
 };
 
 #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
--- a/src/share/vm/opto/callGenerator.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/opto/callGenerator.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -70,6 +70,7 @@
 
 JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
   Compile* C = Compile::current();
+  C->print_inlining_update(this);
 
   if (is_osr()) {
     // The JVMS for a OSR has a single argument (see its TypeFunc).
@@ -126,6 +127,7 @@
 
 JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
   GraphKit kit(jvms);
+  kit.C->print_inlining_update(this);
   bool is_static = method()->is_static();
   address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
                              : SharedRuntime::get_resolve_opt_virtual_call_stub();
@@ -178,6 +180,8 @@
   GraphKit kit(jvms);
   Node* receiver = kit.argument(0);
 
+  kit.C->print_inlining_update(this);
+
   if (kit.C->log() != NULL) {
     kit.C->log()->elem("virtual_call bci='%d'", jvms->bci());
   }
@@ -271,14 +275,13 @@
   LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
     DirectCallGenerator(method, true), _inline_cg(inline_cg) {}
 
-  virtual bool      is_late_inline() const { return true; }
+  virtual bool is_late_inline() const { return true; }
 
   // Convert the CallStaticJava into an inline
   virtual void do_late_inline();
 
   virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
     Compile *C = Compile::current();
-    C->print_inlining_skip(this);
 
     // Record that this call site should be revisited once the main
     // parse is finished.
@@ -296,10 +299,11 @@
   virtual void print_inlining_late(const char* msg) {
     CallNode* call = call_node();
     Compile* C = Compile::current();
-    C->print_inlining_insert(this);
+    C->print_inlining_assert_ready();
     C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), msg);
+    C->print_inlining_move_to(this);
+    C->print_inlining_update_delayed(this);
   }
-
 };
 
 void LateInlineCallGenerator::do_late_inline() {
@@ -360,6 +364,10 @@
     map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
   }
 
+  C->print_inlining_assert_ready();
+
+  C->print_inlining_move_to(this);
+
   // This check is done here because for_method_handle_inline() method
   // needs jvms for inlined state.
   if (!do_late_inline_check(jvms)) {
@@ -367,8 +375,6 @@
     return;
   }
 
-  C->print_inlining_insert(this);
-
   CompileLog* log = C->log();
   if (log != NULL) {
     log->head("late_inline method='%d'", log->identify(method()));
@@ -388,7 +394,7 @@
     C->set_default_node_notes(entry_nn);
   }
 
-  // Now perform the inling using the synthesized JVMState
+  // Now perform the inlining using the synthesized JVMState
   JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
   if (new_jvms == NULL)  return;  // no change
   if (C->failing())      return;
@@ -431,6 +437,7 @@
 
   virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
     JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
+
     if (_input_not_const) {
       // inlining won't be possible so no need to enqueue right now.
       call_node()->set_generator(this);
@@ -439,17 +446,14 @@
     }
     return new_jvms;
   }
-
-  virtual void print_inlining_late(const char* msg) {
-    if (!_input_not_const) return;
-    LateInlineCallGenerator::print_inlining_late(msg);
-  }
 };
 
 bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) {
 
   CallGenerator* cg = for_method_handle_inline(jvms, _caller, method(), _input_not_const);
 
+  Compile::current()->print_inlining_update_delayed(this);
+
   if (!_input_not_const) {
     _attempt++;
   }
@@ -479,8 +483,6 @@
 
   virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
     Compile *C = Compile::current();
-    C->print_inlining_skip(this);
-
     C->add_string_late_inline(this);
 
     JVMState* new_jvms =  DirectCallGenerator::generate(jvms, parent_parser);
@@ -502,7 +504,6 @@
 
   virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
     Compile *C = Compile::current();
-    C->print_inlining_skip(this);
 
     C->add_boxing_late_inline(this);
 
@@ -554,6 +555,8 @@
 
 JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
   Compile* C = Compile::current();
+  C->print_inlining_update(this);
+
   if (C->log() != NULL) {
     C->log()->elem("warm_call bci='%d'", jvms->bci());
   }
@@ -632,6 +635,7 @@
 
 JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
   GraphKit kit(jvms);
+  kit.C->print_inlining_update(this);
   PhaseGVN& gvn = kit.gvn();
   // We need an explicit receiver null_check before checking its type.
   // We share a map with the caller, so his JVMS gets adjusted.
@@ -779,6 +783,9 @@
         assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
         if (cg != NULL && cg->is_inline())
           return cg;
+      } else {
+        const char* msg = "receiver not constant";
+        if (PrintInlining)  C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
       }
     }
     break;
@@ -844,11 +851,13 @@
           // provide us with a type
           speculative_receiver_type = receiver_type->speculative_type();
         }
-
         CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
         assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
         if (cg != NULL && cg->is_inline())
           return cg;
+      } else {
+        const char* msg = "member_name not constant";
+        if (PrintInlining)  C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
       }
     }
     break;
@@ -904,6 +913,7 @@
   if (kit.failing())
     return NULL;  // might happen because of NodeCountInliningCutoff
 
+  kit.C->print_inlining_update(this);
   SafePointNode* slow_map = NULL;
   JVMState* slow_jvms;
   if (slow_ctl != NULL) {
@@ -1017,6 +1027,7 @@
 
 JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
   GraphKit kit(jvms);
+  kit.C->print_inlining_update(this);
   // Take the trap with arguments pushed on the stack.  (Cf. null_check_receiver).
   int nargs = method()->arg_size();
   kit.inc_sp(nargs);
--- a/src/share/vm/opto/compile.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/opto/compile.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -662,6 +662,7 @@
                   _inlining_progress(false),
                   _inlining_incrementally(false),
                   _print_inlining_list(NULL),
+                  _print_inlining_stream(NULL),
                   _print_inlining_idx(0),
                   _preserve_jvm_state(0) {
   C = this;
@@ -723,9 +724,7 @@
   PhaseGVN gvn(node_arena(), estimated_size);
   set_initial_gvn(&gvn);
 
-  if (print_inlining() || print_intrinsics()) {
-    _print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
-  }
+  print_inlining_init();
   { // Scope for timing the parser
     TracePhase t3("parse", &_t_parser, true);
 
@@ -967,6 +966,7 @@
     _inlining_progress(false),
     _inlining_incrementally(false),
     _print_inlining_list(NULL),
+    _print_inlining_stream(NULL),
     _print_inlining_idx(0),
     _preserve_jvm_state(0),
     _allowed_reasons(0) {
@@ -2023,6 +2023,8 @@
   ResourceMark rm;
   int          loop_opts_cnt;
 
+  print_inlining_reinit();
+
   NOT_PRODUCT( verify_graph_edges(); )
 
   print_method(PHASE_AFTER_PARSING);
@@ -3755,30 +3757,114 @@
   }
 }
 
+// The message about the current inlining is accumulated in
+// _print_inlining_stream and transfered into the _print_inlining_list
+// once we know whether inlining succeeds or not. For regular
+// inlining, messages are appended to the buffer pointed by
+// _print_inlining_idx in the _print_inlining_list. For late inlining,
+// a new buffer is added after _print_inlining_idx in the list. This
+// way we can update the inlining message for late inlining call site
+// when the inlining is attempted again.
+void Compile::print_inlining_init() {
+  if (print_inlining() || print_intrinsics()) {
+    _print_inlining_stream = new stringStream();
+    _print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
+  }
+}
+
+void Compile::print_inlining_reinit() {
+  if (print_inlining() || print_intrinsics()) {
+    // Re allocate buffer when we change ResourceMark
+    _print_inlining_stream = new stringStream();
+  }
+}
+
+void Compile::print_inlining_reset() {
+  _print_inlining_stream->reset();
+}
+
+void Compile::print_inlining_commit() {
+  assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
+  // Transfer the message from _print_inlining_stream to the current
+  // _print_inlining_list buffer and clear _print_inlining_stream.
+  _print_inlining_list->at(_print_inlining_idx).ss()->write(_print_inlining_stream->as_string(), _print_inlining_stream->size());
+  print_inlining_reset();
+}
+
+void Compile::print_inlining_push() {
+  // Add new buffer to the _print_inlining_list at current position
+  _print_inlining_idx++;
+  _print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
+}
+
+Compile::PrintInliningBuffer& Compile::print_inlining_current() {
+  return _print_inlining_list->at(_print_inlining_idx);
+}
+
+void Compile::print_inlining_update(CallGenerator* cg) {
+  if (print_inlining() || print_intrinsics()) {
+    if (!cg->is_late_inline()) {
+      if (print_inlining_current().cg() != NULL) {
+        print_inlining_push();
+      }
+      print_inlining_commit();
+    } else {
+      if (print_inlining_current().cg() != cg &&
+          (print_inlining_current().cg() != NULL ||
+           print_inlining_current().ss()->size() != 0)) {
+        print_inlining_push();
+      }
+      print_inlining_commit();
+      print_inlining_current().set_cg(cg);
+    }
+  }
+}
+
+void Compile::print_inlining_move_to(CallGenerator* cg) {
+  // We resume inlining at a late inlining call site. Locate the
+  // corresponding inlining buffer so that we can update it.
+  if (print_inlining()) {
+    for (int i = 0; i < _print_inlining_list->length(); i++) {
+      if (_print_inlining_list->adr_at(i)->cg() == cg) {
+        _print_inlining_idx = i;
+        return;
+      }
+    }
+    ShouldNotReachHere();
+  }
+}
+
+void Compile::print_inlining_update_delayed(CallGenerator* cg) {
+  if (print_inlining()) {
+    assert(_print_inlining_stream->size() > 0, "missing inlining msg");
+    assert(print_inlining_current().cg() == cg, "wrong entry");
+    // replace message with new message
+    _print_inlining_list->at_put(_print_inlining_idx, PrintInliningBuffer());
+    print_inlining_commit();
+    print_inlining_current().set_cg(cg);
+  }
+}
+
+void Compile::print_inlining_assert_ready() {
+  assert(!_print_inlining || _print_inlining_stream->size() == 0, "loosing data");
+}
+
 void Compile::dump_inlining() {
-  if (print_inlining() || print_intrinsics()) {
+  bool do_print_inlining = print_inlining() || print_intrinsics();
+  if (do_print_inlining) {
     // Print inlining message for candidates that we couldn't inline
-    // for lack of space or non constant receiver
+    // for lack of space
     for (int i = 0; i < _late_inlines.length(); i++) {
       CallGenerator* cg = _late_inlines.at(i);
-      cg->print_inlining_late("live nodes > LiveNodeCountInliningCutoff");
-    }
-    Unique_Node_List useful;
-    useful.push(root());
-    for (uint next = 0; next < useful.size(); ++next) {
-      Node* n  = useful.at(next);
-      if (n->is_Call() && n->as_Call()->generator() != NULL && n->as_Call()->generator()->call_node() == n) {
-        CallNode* call = n->as_Call();
-        CallGenerator* cg = call->generator();
-        cg->print_inlining_late("receiver not constant");
-      }
-      uint max = n->len();
-      for ( uint i = 0; i < max; ++i ) {
-        Node *m = n->in(i);
-        if ( m == NULL ) continue;
-        useful.push(m);
+      if (!cg->is_mh_late_inline()) {
+        const char* msg = "live nodes > LiveNodeCountInliningCutoff";
+        if (do_print_inlining) {
+          cg->print_inlining_late(msg);
+        }
       }
     }
+  }
+  if (do_print_inlining) {
     for (int i = 0; i < _print_inlining_list->length(); i++) {
       tty->print(_print_inlining_list->adr_at(i)->ss()->as_string());
     }
--- a/src/share/vm/opto/compile.hpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/opto/compile.hpp	Fri Apr 11 10:31:25 2014 +0200
@@ -416,6 +416,7 @@
     void set_cg(CallGenerator* cg) { _cg = cg; }
   };
 
+  stringStream* _print_inlining_stream;
   GrowableArray<PrintInliningBuffer>* _print_inlining_list;
   int _print_inlining_idx;
 
@@ -433,33 +434,24 @@
 
   void* _replay_inline_data; // Pointer to data loaded from file
 
+  void print_inlining_init();
+  void print_inlining_reinit();
+  void print_inlining_commit();
+  void print_inlining_push();
+  PrintInliningBuffer& print_inlining_current();
+
  public:
 
   outputStream* print_inlining_stream() const {
-    return _print_inlining_list->adr_at(_print_inlining_idx)->ss();
+    assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
+    return _print_inlining_stream;
   }
 
-  void print_inlining_skip(CallGenerator* cg) {
-    if (_print_inlining) {
-      _print_inlining_list->adr_at(_print_inlining_idx)->set_cg(cg);
-      _print_inlining_idx++;
-      _print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
-    }
-  }
-
-  void print_inlining_insert(CallGenerator* cg) {
-    if (_print_inlining) {
-      for (int i = 0; i < _print_inlining_list->length(); i++) {
-        if (_print_inlining_list->adr_at(i)->cg() == cg) {
-          _print_inlining_list->insert_before(i+1, PrintInliningBuffer());
-          _print_inlining_idx = i+1;
-          _print_inlining_list->adr_at(i)->set_cg(NULL);
-          return;
-        }
-      }
-      ShouldNotReachHere();
-    }
-  }
+  void print_inlining_update(CallGenerator* cg);
+  void print_inlining_update_delayed(CallGenerator* cg);
+  void print_inlining_move_to(CallGenerator* cg);
+  void print_inlining_assert_ready();
+  void print_inlining_reset();
 
   void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) {
     stringStream ss;
--- a/src/share/vm/opto/doCall.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/opto/doCall.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -294,6 +294,8 @@
   // There was no special inlining tactic, or it bailed out.
   // Use a more generic tactic, like a simple call.
   if (call_does_dispatch) {
+    const char* msg = "virtual call";
+    if (PrintInlining) print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
     return CallGenerator::for_virtual_call(callee, vtable_index);
   } else {
     // Class Hierarchy Analysis or Type Profile reveals a unique target,
@@ -396,6 +398,8 @@
   // our contribution to it is cleaned up right here.
   kill_dead_locals();
 
+  C->print_inlining_assert_ready();
+
   // Set frequently used booleans
   const bool is_virtual = bc() == Bytecodes::_invokevirtual;
   const bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface;
@@ -531,7 +535,8 @@
     // intrinsic was expecting to optimize. Should always be possible to
     // get a normal java call that may inline in that case
     cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
-    if ((new_jvms = cg->generate(jvms, this)) == NULL) {
+    new_jvms = cg->generate(jvms, this);
+    if (new_jvms == NULL) {
       guarantee(failing(), "call failed to generate:  calls should work");
       return;
     }
--- a/src/share/vm/opto/library_call.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/opto/library_call.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -620,6 +620,7 @@
     }
     // Push the result from the inlined method onto the stack.
     kit.push_result();
+    C->print_inlining_update(this);
     return kit.transfer_exceptions_into_jvms();
   }
 
@@ -637,6 +638,7 @@
     }
   }
   C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
+  C->print_inlining_update(this);
   return NULL;
 }
 
--- a/src/share/vm/prims/whitebox.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/prims/whitebox.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -438,6 +438,30 @@
   return (mh->queued_for_compilation() || nm != NULL);
 WB_END
 
+class VM_WhiteBoxOperation : public VM_Operation {
+ public:
+  VM_WhiteBoxOperation()                         { }
+  VMOp_Type type()                  const        { return VMOp_WhiteBoxOperation; }
+  bool allow_nested_vm_operations() const        { return true; }
+};
+
+class AlwaysFalseClosure : public BoolObjectClosure {
+ public:
+  bool do_object_b(oop p) { return false; }
+};
+
+static AlwaysFalseClosure always_false;
+
+class VM_WhiteBoxCleanMethodData : public VM_WhiteBoxOperation {
+ public:
+  VM_WhiteBoxCleanMethodData(MethodData* mdo) : _mdo(mdo) { }
+  void doit() {
+    _mdo->clean_method_data(&always_false);
+  }
+ private:
+  MethodData* _mdo;
+};
+
 WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
   CHECK_JNI_EXCEPTION(env);
@@ -453,6 +477,8 @@
     for (int i = 0; i < arg_count; i++) {
       mdo->set_arg_modified(i, 0);
     }
+    VM_WhiteBoxCleanMethodData op(mdo);
+    VMThread::execute(&op);
   }
 
   mh->clear_not_c1_compilable();
--- a/src/share/vm/runtime/sharedRuntime.cpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Fri Apr 11 10:31:25 2014 +0200
@@ -1268,8 +1268,6 @@
       }
 #endif
       if (is_virtual) {
-        nmethod* nm = callee_nm;
-        if (nm == NULL) CodeCache::find_blob(caller_frame.pc());
         CompiledIC* inline_cache = CompiledIC_before(caller_nm, caller_frame.pc());
         if (inline_cache->is_clean()) {
           inline_cache->set_to_monomorphic(virtual_call_info);
--- a/src/share/vm/runtime/vm_operations.hpp	Tue Apr 08 13:50:58 2014 +0200
+++ b/src/share/vm/runtime/vm_operations.hpp	Fri Apr 11 10:31:25 2014 +0200
@@ -97,6 +97,7 @@
   template(Exit)                                  \
   template(LinuxDllLoad)                          \
   template(RotateGCLog)                           \
+  template(WhiteBoxOperation)                     \
 
 class VM_Operation: public CHeapObj<mtInternal> {
  public:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/profiling/spectrapredefineclass/Agent.java	Fri Apr 11 10:31:25 2014 +0200
@@ -0,0 +1,142 @@
+/*
+ * 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.security.*;
+import java.lang.instrument.*;
+import java.lang.reflect.*;
+import java.lang.management.ManagementFactory;
+import com.sun.tools.attach.VirtualMachine;
+
+class A {
+    void m() {
+    }
+}
+
+class B extends A {
+    void m() {
+    }
+}
+
+class C extends A {
+    void m() {
+    }
+}
+
+class Test {
+
+    static public void m() throws Exception {
+        for (int i = 0; i < 20000; i++) {
+            m1(a);
+        }
+        for (int i = 0; i < 4; i++) {
+            m1(b);
+        }
+    }
+
+    static boolean m1(A a) {
+        boolean res =  Agent.m2(a);
+        return res;
+    }
+
+    static public A a = new A();
+    static public B b = new B();
+    static public C c = new C();
+}
+
+public class Agent implements ClassFileTransformer {
+
+
+    static class MemoryChunk {
+        MemoryChunk other;
+        long[] array;
+        MemoryChunk(MemoryChunk other) {
+            other = other;
+            array = new long[1024 * 1024 * 1024];
+        }
+    }
+
+    static public boolean m2(A a) {
+        boolean res = false;
+        if (a.getClass() == B.class) {
+            a.m();
+        } else {
+            res = true;
+        }
+        return res;
+    }
+
+    static public void main(String[] args) throws Exception {
+        // Create speculative trap entries
+        Test.m();
+
+        String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
+        int p = nameOfRunningVM.indexOf('@');
+        String pid = nameOfRunningVM.substring(0, p);
+
+        // Make the nmethod go away
+        for (int i = 0; i < 10; i++) {
+            System.gc();
+        }
+
+        // Redefine class
+        try {
+            VirtualMachine vm = VirtualMachine.attach(pid);
+            vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", "");
+            vm.detach();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        Test.m();
+        // GC will hit dead method pointer
+        for (int i = 0; i < 10; i++) {
+            System.gc();
+        }
+    }
+
+    public synchronized byte[] transform(final ClassLoader classLoader,
+                                         final String className,
+                                         Class<?> classBeingRedefined,
+                                         ProtectionDomain protectionDomain,
+                                         byte[] classfileBuffer) {
+        System.out.println("Transforming class " + className);
+        return classfileBuffer;
+    }
+
+    public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
+
+        try {
+            instrumentation.retransformClasses(to_redefine);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
+        Agent transformer = new Agent();
+        instrumentation.addTransformer(transformer, true);
+
+        redefine(agentArgs, instrumentation, Test.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/compiler/profiling/spectrapredefineclass/Launcher.java	Fri Apr 11 10:31:25 2014 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.io.PrintWriter;
+import com.oracle.java.testlibrary.*;
+
+/*
+ * @test
+ * @bug 8038636
+ * @library /testlibrary
+ * @build Agent
+ * @run main ClassFileInstaller Agent
+ * @run main Launcher
+ * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -Xmx1M -XX:ReservedCodeCacheSize=3M Agent
+ */
+public class Launcher {
+    public static void main(String[] args) throws Exception  {
+
+      PrintWriter pw = new PrintWriter("MANIFEST.MF");
+      pw.println("Agent-Class: Agent");
+      pw.println("Can-Retransform-Classes: true");
+      pw.close();
+
+      ProcessBuilder pb = new ProcessBuilder();
+      pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"});
+      pb.start().waitFor();
+    }
+}