src/share/vm/runtime/sharedRuntime.cpp

Print this page
rev 2893 : 7121756: Improve C1 inlining policy by using profiling at call sites
Summary: profile based recompilation of methods with C1 with more inlining.
Reviewed-by:

@@ -76,18 +76,23 @@
 # include "nativeInst_ppc.hpp"
 # include "vmreg_ppc.inline.hpp"
 #endif
 #ifdef COMPILER1
 #include "c1/c1_Runtime1.hpp"
+#include "runtime/compilationPolicy.hpp"
 #endif
 
 // Shared stub locations
 RuntimeStub*        SharedRuntime::_wrong_method_blob;
 RuntimeStub*        SharedRuntime::_ic_miss_blob;
 RuntimeStub*        SharedRuntime::_resolve_opt_virtual_call_blob;
 RuntimeStub*        SharedRuntime::_resolve_virtual_call_blob;
 RuntimeStub*        SharedRuntime::_resolve_static_call_blob;
+#ifdef COMPILER1
+RuntimeStub*        SharedRuntime::_resolve_profile_call_blob;
+RuntimeStub*        SharedRuntime::_resolve_static_profile_call_blob;
+#endif
 
 DeoptimizationBlob* SharedRuntime::_deopt_blob;
 RicochetBlob*       SharedRuntime::_ricochet_blob;
 
 SafepointBlob*      SharedRuntime::_polling_page_safepoint_handler_blob;

@@ -103,10 +108,14 @@
   _wrong_method_blob                   = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method),         "wrong_method_stub");
   _ic_miss_blob                        = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss), "ic_miss_stub");
   _resolve_opt_virtual_call_blob       = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C),  "resolve_opt_virtual_call");
   _resolve_virtual_call_blob           = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),      "resolve_virtual_call");
   _resolve_static_call_blob            = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),       "resolve_static_call");
+#ifdef COMPILER1
+  _resolve_profile_call_blob           = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_profile_call_C),      "resolve_profile_call");
+  _resolve_static_profile_call_blob    = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_profile_call_C),"resolve_static_profile_call");
+#endif
 
   _polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), false);
   _polling_page_return_handler_blob    = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), true);
 
   generate_ricochet_blob();

@@ -1184,10 +1193,31 @@
   methodHandle callee_method = call_info.selected_method();
 
   assert((!is_virtual && invoke_code == Bytecodes::_invokestatic) ||
          ( is_virtual && invoke_code != Bytecodes::_invokestatic), "inconsistent bytecode");
 
+  bool is_profiled = false; 
+
+#ifdef COMPILER1
+  is_profiled = caller_nm->is_profiled_call(caller_frame.pc());
+  if (is_profiled) {
+    if (callee_method->code_size() > SimpleProfiledCompPolicy::max_inline_size()) {
+      is_profiled = false;
+    }
+    if (is_profiled) {
+      vframeStream vfst(thread);
+      methodOop m = vfst.method();
+      int bci = vfst.bci();
+      
+      CounterData* profile = m->method_data()->bci_to_data(bci)->as_CounterData();
+      
+      profile->init_if_first_seen();
+    }
+  }
+#endif
+
+
 #ifndef PRODUCT
   // tracing/debugging/statistics
   int *addr = (is_optimized) ? (&_resolve_opt_virtual_ctr) :
                 (is_virtual) ? (&_resolve_virtual_ctr) :
                                (&_resolve_static_ctr);

@@ -1232,15 +1262,15 @@
   if (is_virtual) {
     assert(receiver.not_null(), "sanity check");
     bool static_bound = call_info.resolved_method()->can_be_statically_bound();
     KlassHandle h_klass(THREAD, receiver->klass());
     CompiledIC::compute_monomorphic_entry(callee_method, h_klass,
-                     is_optimized, static_bound, virtual_call_info,
+                                          is_optimized, static_bound, virtual_call_info, is_profiled,
                      CHECK_(methodHandle()));
   } else {
     // static call
-    CompiledStaticCall::compute_entry(callee_method, static_call_info);
+    CompiledStaticCall::compute_entry(callee_method, static_call_info, is_profiled);
   }
 
   // grab lock, check for deoptimization and potentially patch caller
   {
     MutexLocker ml_patch(CompiledIC_lock);

@@ -1258,10 +1288,22 @@
 #endif
       if (is_virtual) {
         CompiledIC* inline_cache = CompiledIC_before(caller_frame.pc());
         if (inline_cache->is_clean()) {
           inline_cache->set_to_monomorphic(virtual_call_info);
+#ifdef COMPILER1
+          if (is_profiled && !is_optimized) {
+            assert(invoke_code == Bytecodes::_invokevirtual || invoke_code == Bytecodes::_invokeinterface, "unexpected call");
+            vframeStream vfst(thread);
+            methodOop m = vfst.method();
+            int bci = vfst.bci();
+            
+            VirtualCallData* profile = m->method_data()->bci_to_data(bci)->as_VirtualCallData();
+
+            profile->new_receiver(receiver);
+          }
+#endif
         }
       } else {
         CompiledStaticCall* ssc = compiledStaticCall_before(caller_frame.pc());
         if (ssc->is_clean()) ssc->set(static_call_info);
       }

@@ -1389,13 +1431,79 @@
   // return compiled code entry point after potential safepoints
   assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
   return callee_method->verified_code_entry();
 JRT_END
 
+#ifdef COMPILER1
+methodHandle SharedRuntime::resolve_profile_helper(JavaThread *thread, TRAPS) {
+  ResourceMark rm(thread);
+  RegisterMap cbl_map(thread, false);
+  frame caller_frame = thread->last_frame().sender(&cbl_map);
+  
+  CodeBlob* cb = caller_frame.cb();
+  guarantee(cb != NULL && cb->is_nmethod(), "must be called from nmethod");
+  nmethodLocker caller_lock((nmethod*)cb);
+  CallInfo call_info;
+  Bytecodes::Code invoke_code = Bytecodes::_illegal;
+  Handle receiver = find_callee_info(thread, invoke_code,
+                                     call_info, CHECK_(methodHandle()));
+
+  return call_info.selected_method();
+}
+
+JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_profile_call_C(JavaThread *thread ))
+  methodHandle callee_method;
+  JRT_BLOCK
+  {
+    callee_method = resolve_profile_helper(thread, CHECK_NULL);
+ 
+    bool fix_call = SimpleProfiledCompPolicy::profile_overflow_event(thread, CHECK_NULL);
+    
+    if (fix_call) {
+      ResourceMark rm;
+      RegisterMap map(thread, false);
+      frame fr =  thread->last_frame().sender(&map);
+      
+      MutexLocker ml_patch(CompiledIC_lock);
+
+      CompiledIC* inline_cache = CompiledIC_before(fr.pc());
+
+      inline_cache->drop_profiling();
+    }
+    thread->set_vm_result(callee_method());
+  }
+  JRT_BLOCK_END
+  // return compiled code entry point after potential safepoints
+  assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
+  return callee_method->verified_code_entry();
+JRT_END
+
+JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_profile_call_C(JavaThread *thread ))
+  methodHandle callee_method;
+  JRT_BLOCK
+  {
+    callee_method = resolve_profile_helper(thread, CHECK_NULL);
+
+    bool fix_call = SimpleProfiledCompPolicy::profile_overflow_event(thread, CHECK_NULL);
 
+    if (fix_call) {
 
+      RegisterMap map(thread, false);
+      frame fr =  thread->last_frame().sender(&map);
 
+      MutexLocker ml_patch(CompiledIC_lock);
+      CompiledStaticCall* ssc = compiledStaticCall_before(fr.pc());
+      ssc->drop_profiling();
+    }
+    thread->set_vm_result(callee_method());
+  }
+  JRT_BLOCK_END
+  // return compiled code entry point after potential safepoints
+  assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
+  return callee_method->verified_code_entry();
+JRT_END
+#endif
 
 methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
   ResourceMark rm(thread);
   CallInfo call_info;
   Bytecodes::Code bc;

@@ -1498,24 +1606,52 @@
         }
       }
 
       if (should_be_mono) {
 
+        bool is_profiled = false;
+#ifdef COMPILER1
+        is_profiled = ((nmethod*)cb)->is_profiled_call(caller_frame.pc());
+#endif
         // We have a path that was monomorphic but was going interpreted
         // and now we have (or had) a compiled entry. We correct the IC
         // by using a new icBuffer.
         CompiledICInfo info;
         KlassHandle receiver_klass(THREAD, receiver()->klass());
         inline_cache->compute_monomorphic_entry(callee_method,
                                                 receiver_klass,
                                                 inline_cache->is_optimized(),
                                                 false,
-                                                info, CHECK_(methodHandle()));
+                                                info, is_profiled, CHECK_(methodHandle()));
+#ifdef COMPILER1
+        if (is_profiled) {
+          vframeStream vfst(thread);
+          methodOop m = vfst.method();
+          int bci = vfst.bci();
+          
+          CounterData* profile = m->method_data()->bci_to_data(bci)->as_CounterData();
+          
+          profile->init_if_first_seen();
+        }
+#endif
+
         inline_cache->set_to_monomorphic(info);
       } else if (!inline_cache->is_megamorphic() && !inline_cache->is_clean()) {
         // Change to megamorphic
         inline_cache->set_to_megamorphic(&call_info, bc, CHECK_(methodHandle()));
+#ifdef COMPILER1
+        if (((nmethod*)cb)->is_profiled_call(caller_frame.pc())) {
+          vframeStream vfst(thread);
+          methodOop m = vfst.method();
+          int bci = vfst.bci();
+          
+          VirtualCallData* profile = m->method_data()->bci_to_data(bci)->as_VirtualCallData();
+          
+          profile->new_receiver(receiver);
+        }
+#endif
+        
       } else {
         // Either clean or megamorphic
       }
     }
   } // Release CompiledIC_lock

@@ -1679,10 +1815,15 @@
   // handle adapters are doing the required MethodHandle chain work.
   if (nm->is_method_handle_return(return_pc)) {
     return;
   }
 
+  bool is_profiled = false;
+#ifdef COMPILER1
+  is_profiled = nm->is_profiled_call(caller_pc+frame::pc_return_offset);
+#endif
+
   // There is a benign race here. We could be attempting to patch to a compiled
   // entry point at the same time the callee is being deoptimized. If that is
   // the case then entry_point may in fact point to a c2i and we'd patch the
   // call site with the same old data. clear_code will set code() to NULL
   // at the end of it. If we happen to see that NULL then we can skip trying

@@ -1716,21 +1857,29 @@
            typ != relocInfo::opt_virtual_call_type &&
            typ != relocInfo::static_stub_type) {
         return;
       }
       address destination = call->destination();
-      if (destination != entry_point) {
+      address stub = NULL;
+      if (is_profiled) {
+        stub = CompiledProfile::find_profile_stub(call);
+      }
+      if (destination != entry_point && !CompiledProfile::is_call_to_stub(call, stub)) {
         CodeBlob* callee = CodeCache::find_blob(destination);
         // callee == cb seems weird. It means calling interpreter thru stub.
         if (callee == cb || callee->is_adapter_blob()) {
           // static call or optimized virtual
           if (TraceCallFixup) {
             tty->print("fixup callsite           at " INTPTR_FORMAT " to compiled code for", caller_pc);
             moop->print_short_name(tty);
             tty->print_cr(" to " INTPTR_FORMAT, entry_point);
           }
+          if (is_profiled) {
+            CompiledProfile::set_up_profiling(call, stub, entry_point);
+          } else {
           call->set_destination_mt_safe(entry_point);
+          }
         } else {
           if (TraceCallFixup) {
             tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc);
             moop->print_short_name(tty);
             tty->print_cr(" to " INTPTR_FORMAT, entry_point);