< prev index next >

src/hotspot/share/opto/runtime.cpp

Print this page
@@ -30,10 +30,11 @@
  #include "code/nmethod.hpp"
  #include "code/pcDesc.hpp"
  #include "code/scopeDesc.hpp"
  #include "code/vtableStubs.hpp"
  #include "compiler/compileBroker.hpp"
+ #include "compiler/compilerDefinitions.inline.hpp"
  #include "compiler/oopMap.hpp"
  #include "gc/g1/g1HeapRegion.hpp"
  #include "gc/shared/barrierSet.hpp"
  #include "gc/shared/collectedHeap.hpp"
  #include "gc/shared/gcLocker.hpp"

@@ -63,20 +64,23 @@
  #include "prims/jvmtiExport.hpp"
  #include "runtime/atomic.hpp"
  #include "runtime/frame.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
+ #include "runtime/java.hpp"
  #include "runtime/javaCalls.hpp"
+ #include "runtime/perfData.inline.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/stackWatermarkSet.hpp"
  #include "runtime/synchronizer.hpp"
  #include "runtime/threadCritical.hpp"
  #include "runtime/threadWXSetters.inline.hpp"
  #include "runtime/vframe.hpp"
  #include "runtime/vframeArray.hpp"
  #include "runtime/vframe_hp.hpp"
+ #include "services/management.hpp"
  #include "utilities/copy.hpp"
  #include "utilities/preserveException.hpp"
  
  
  // For debugging purposes:

@@ -98,20 +102,25 @@
  C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE, C2_JVMTI_STUB_FIELD_DEFINE)
  #undef C2_BLOB_FIELD_DEFINE
  #undef C2_STUB_FIELD_DEFINE
  #undef C2_JVMTI_STUB_FIELD_DEFINE
  
+ 
  #define C2_BLOB_NAME_DEFINE(name, type)  "C2 Runtime " # name "_blob",
  #define C2_STUB_NAME_DEFINE(name, f, t, r)  "C2 Runtime " # name,
  #define C2_JVMTI_STUB_NAME_DEFINE(name)  "C2 Runtime " # name,
  const char* OptoRuntime::_stub_names[] = {
    C2_STUBS_DO(C2_BLOB_NAME_DEFINE, C2_STUB_NAME_DEFINE, C2_JVMTI_STUB_NAME_DEFINE)
  };
  #undef C2_BLOB_NAME_DEFINE
  #undef C2_STUB_NAME_DEFINE
  #undef C2_JVMTI_STUB_NAME_DEFINE
  
+ address OptoRuntime::_vtable_must_compile_Java                    = nullptr;
+ 
+ PerfCounter* _perf_OptoRuntime_class_init_barrier_redundant_count = nullptr;
+ 
  // This should be called in an assertion at the start of OptoRuntime routines
  // which are entered from compiled code (all of them)
  #ifdef ASSERT
  static bool check_compiled_frame(JavaThread* thread) {
    assert(thread->last_frame().is_runtime_frame(), "cannot call runtime directly from compiled code");

@@ -172,10 +181,11 @@
                    true,                                                 \
                    false);                                               \
    if (STUB_FIELD_NAME(name) == nullptr) { return false; }               \
  
  bool OptoRuntime::generate(ciEnv* env) {
+   init_counters();
  
    C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB, GEN_C2_JVMTI_STUB)
  
    return true;
  }

@@ -199,11 +209,11 @@
                                     const char *name, int is_fancy_jump,
                                     bool pass_tls,
                                     bool return_pc) {
  
    // Matching the default directive, we currently have no method to match.
-   DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_full_optimization));
+   DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompilerThread::current()->compiler());
    ResourceMark rm;
    Compile C(env, gen, C_function, name, is_fancy_jump, pass_tls, return_pc, directive);
    DirectivesStack::release(directive);
    return  C.stub_entry_point();
  }

@@ -242,11 +252,11 @@
  //=============================allocation======================================
  // We failed the fast-path allocation.  Now we need to do a scavenge or GC
  // and try allocation again.
  
  // object allocation
- JRT_BLOCK_ENTRY(void, OptoRuntime::new_instance_C(Klass* klass, JavaThread* current))
+ JRT_BLOCK_ENTRY_PROF(void, OptoRuntime, new_instance_C, OptoRuntime::new_instance_C(Klass* klass, JavaThread* current))
    JRT_BLOCK;
  #ifndef PRODUCT
    SharedRuntime::_new_instance_ctr++;         // new instance requires GC
  #endif
    assert(check_compiled_frame(current), "incorrect caller");

@@ -280,11 +290,11 @@
    SharedRuntime::on_slowpath_allocation_exit(current);
  JRT_END
  
  
  // array allocation
- JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, JavaThread* current))
+ JRT_BLOCK_ENTRY_PROF(void, OptoRuntime, new_array_C, OptoRuntime::new_array_C(Klass* array_type, int len, JavaThread* current))
    JRT_BLOCK;
  #ifndef PRODUCT
    SharedRuntime::_new_array_ctr++;            // new array requires GC
  #endif
    assert(check_compiled_frame(current), "incorrect caller");

@@ -317,11 +327,11 @@
    // inform GC that we won't do card marks for initializing writes.
    SharedRuntime::on_slowpath_allocation_exit(current);
  JRT_END
  
  // array allocation without zeroing
- JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_nozero_C(Klass* array_type, int len, JavaThread* current))
+ JRT_BLOCK_ENTRY_PROF(void, OptoRuntime, new_array_nozero_C, OptoRuntime::new_array_nozero_C(Klass* array_type, int len, JavaThread* current))
    JRT_BLOCK;
  #ifndef PRODUCT
    SharedRuntime::_new_array_ctr++;            // new array requires GC
  #endif
    assert(check_compiled_frame(current), "incorrect caller");

@@ -369,11 +379,11 @@
  JRT_END
  
  // Note: multianewarray for one dimension is handled inline by GraphKit::new_array.
  
  // multianewarray for 2 dimensions
- JRT_ENTRY(void, OptoRuntime::multianewarray2_C(Klass* elem_type, int len1, int len2, JavaThread* current))
+ JRT_ENTRY_PROF(void, OptoRuntime, multianewarray2_C, OptoRuntime::multianewarray2_C(Klass* elem_type, int len1, int len2, JavaThread* current))
  #ifndef PRODUCT
    SharedRuntime::_multi2_ctr++;                // multianewarray for 1 dimension
  #endif
    assert(check_compiled_frame(current), "incorrect caller");
    assert(elem_type->is_klass(), "not a class");

@@ -385,11 +395,11 @@
    deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION);
    current->set_vm_result(obj);
  JRT_END
  
  // multianewarray for 3 dimensions
- JRT_ENTRY(void, OptoRuntime::multianewarray3_C(Klass* elem_type, int len1, int len2, int len3, JavaThread* current))
+ JRT_ENTRY_PROF(void, OptoRuntime, multianewarray3_C, OptoRuntime::multianewarray3_C(Klass* elem_type, int len1, int len2, int len3, JavaThread* current))
  #ifndef PRODUCT
    SharedRuntime::_multi3_ctr++;                // multianewarray for 1 dimension
  #endif
    assert(check_compiled_frame(current), "incorrect caller");
    assert(elem_type->is_klass(), "not a class");

@@ -402,11 +412,11 @@
    deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION);
    current->set_vm_result(obj);
  JRT_END
  
  // multianewarray for 4 dimensions
- JRT_ENTRY(void, OptoRuntime::multianewarray4_C(Klass* elem_type, int len1, int len2, int len3, int len4, JavaThread* current))
+ JRT_ENTRY_PROF(void, OptoRuntime, multianewarray4_C, OptoRuntime::multianewarray4_C(Klass* elem_type, int len1, int len2, int len3, int len4, JavaThread* current))
  #ifndef PRODUCT
    SharedRuntime::_multi4_ctr++;                // multianewarray for 1 dimension
  #endif
    assert(check_compiled_frame(current), "incorrect caller");
    assert(elem_type->is_klass(), "not a class");

@@ -438,11 +448,11 @@
    oop obj = ArrayKlass::cast(elem_type)->multi_allocate(5, dims, THREAD);
    deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION);
    current->set_vm_result(obj);
  JRT_END
  
- JRT_ENTRY(void, OptoRuntime::multianewarrayN_C(Klass* elem_type, arrayOopDesc* dims, JavaThread* current))
+ JRT_ENTRY_PROF(void, OptoRuntime, multianewarrayN_C, OptoRuntime::multianewarrayN_C(Klass* elem_type, arrayOopDesc* dims, JavaThread* current))
    assert(check_compiled_frame(current), "incorrect caller");
    assert(elem_type->is_klass(), "not a class");
    assert(oop(dims)->is_typeArray(), "not an array");
  
    ResourceMark rm;

@@ -456,11 +466,11 @@
    oop obj = ArrayKlass::cast(elem_type)->multi_allocate(len, c_dims, THREAD);
    deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION);
    current->set_vm_result(obj);
  JRT_END
  
- JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notify_C(oopDesc* obj, JavaThread* current))
+ JRT_BLOCK_ENTRY_PROF(void, OptoRuntime, monitor_notify_C, OptoRuntime::monitor_notify_C(oopDesc* obj, JavaThread* current))
  
    // Very few notify/notifyAll operations find any threads on the waitset, so
    // the dominant fast-path is to simply return.
    // Relatedly, it's critical that notify/notifyAll be fast in order to
    // reduce lock hold times.

@@ -478,11 +488,11 @@
    Handle h_obj(current, obj);
    ObjectSynchronizer::notify(h_obj, CHECK);
    JRT_BLOCK_END;
  JRT_END
  
- JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notifyAll_C(oopDesc* obj, JavaThread* current))
+ JRT_BLOCK_ENTRY_PROF(void, OptoRuntime, monitor_notifyAll_C, OptoRuntime::monitor_notifyAll_C(oopDesc* obj, JavaThread* current))
  
    if (!SafepointSynchronize::is_synchronizing() ) {
      if (ObjectSynchronizer::quick_notify(obj, current, true)) {
        return;
      }

@@ -1542,11 +1552,11 @@
  static void trace_exception(outputStream* st, oop exception_oop, address exception_pc, const char* msg);
  
  // The method is an entry that is always called by a C++ method not
  // directly from compiled code. Compiled code will call the C++ method following.
  // We can't allow async exception to be installed during  exception processing.
- JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* current, nmethod* &nm))
+ JRT_ENTRY_NO_ASYNC_PROF(address, OptoRuntime, handle_exception_C_helper, OptoRuntime::handle_exception_C_helper(JavaThread* current, nmethod* &nm))
    // The frame we rethrow the exception to might not have been processed by the GC yet.
    // The stack watermark barrier takes care of detecting that and ensuring the frame
    // has updated oops.
    StackWatermarkSet::after_unwind(current);
  

@@ -1818,10 +1828,24 @@
    const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0,fields);
  
    return TypeFunc::make(domain,range);
  }
  
+ const TypeFunc *OptoRuntime::class_init_barrier_Type() {
+   // create input type (domain)
+   const Type** fields = TypeTuple::fields(1);
+   fields[TypeFunc::Parms+0] = TypeKlassPtr::NOTNULL;
+   // // The JavaThread* is passed to each routine as the last argument
+   // fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL;  // JavaThread *; Executing thread
+   const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+1, fields);
+ 
+   // create result type (range)
+   fields = TypeTuple::fields(0);
+   const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields);
+   return TypeFunc::make(domain,range);
+ }
+ 
  #if INCLUDE_JFR
  const TypeFunc *OptoRuntime::class_id_load_barrier_Type() {
    // create input type (domain)
    const Type **fields = TypeTuple::fields(1);
    fields[TypeFunc::Parms+0] = TypeInstPtr::KLASS;

@@ -1834,10 +1858,26 @@
  
    return TypeFunc::make(domain,range);
  }
  #endif
  
+ //-----------------------------------------------------------------------------
+ // runtime upcall support
+ const TypeFunc *OptoRuntime::runtime_up_call_Type() {
+   // create input type (domain)
+   const Type **fields = TypeTuple::fields(1);
+   fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM; // Thread-local storage
+   const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1,fields);
+ 
+   // create result type (range)
+   fields = TypeTuple::fields(0);
+ 
+   const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0,fields);
+ 
+   return TypeFunc::make(domain,range);
+ }
+ 
  //-----------------------------------------------------------------------------
  // Dtrace support.  entry and exit probes have the same signature
  const TypeFunc *OptoRuntime::dtrace_method_entry_exit_Type() {
    // create input type (domain)
    const Type **fields = TypeTuple::fields(2);

@@ -1868,16 +1908,25 @@
  
    return TypeFunc::make(domain,range);
  }
  
  
- JRT_ENTRY_NO_ASYNC(void, OptoRuntime::register_finalizer_C(oopDesc* obj, JavaThread* current))
+ JRT_ENTRY_NO_ASYNC_PROF(void, OptoRuntime, register_finalizer_C, OptoRuntime::register_finalizer_C(oopDesc* obj, JavaThread* current))
    assert(oopDesc::is_oop(obj), "must be a valid oop");
    assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
    InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
  JRT_END
  
+ JRT_ENTRY_NO_ASYNC_PROF(void, OptoRuntime, class_init_barrier_C, OptoRuntime::class_init_barrier_C(Klass* k, JavaThread* current))
+   InstanceKlass* ik = InstanceKlass::cast(k);
+   if (ik->should_be_initialized()) {
+     ik->initialize(CHECK);
+   } else if (UsePerfData) {
+     _perf_OptoRuntime_class_init_barrier_redundant_count->inc();
+   }
+ JRT_END
+ 
  //-----------------------------------------------------------------------------
  
  NamedCounter * volatile OptoRuntime::_named_counters = nullptr;
  
  //

@@ -1974,5 +2023,71 @@
    tempst.print(" at " INTPTR_FORMAT,  p2i(exception_pc));
    tempst.print("]");
  
    st->print_raw_cr(tempst.freeze());
  }
+ 
+ #define DO_COUNTERS2(macro2, macro1) \
+   macro2(OptoRuntime, new_instance_C) \
+   macro2(OptoRuntime, new_array_C) \
+   macro2(OptoRuntime, new_array_nozero_C) \
+   macro2(OptoRuntime, multianewarray2_C) \
+   macro2(OptoRuntime, multianewarray3_C) \
+   macro2(OptoRuntime, multianewarray4_C) \
+   macro2(OptoRuntime, multianewarrayN_C) \
+   macro2(OptoRuntime, monitor_notify_C) \
+   macro2(OptoRuntime, monitor_notifyAll_C) \
+   macro2(OptoRuntime, handle_exception_C_helper) \
+   macro2(OptoRuntime, register_finalizer_C) \
+   macro2(OptoRuntime, class_init_barrier_C) \
+   macro1(OptoRuntime, class_init_barrier_redundant)
+ 
+ #define INIT_COUNTER_TIME_AND_CNT(sub, name) \
+   NEWPERFTICKCOUNTERS(_perf_##sub##_##name##_timer, SUN_CI, #sub "::" #name); \
+   NEWPERFEVENTCOUNTER(_perf_##sub##_##name##_count, SUN_CI, #sub "::" #name "_count");
+ 
+ #define INIT_COUNTER_CNT(sub, name) \
+   NEWPERFEVENTCOUNTER(_perf_##sub##_##name##_count, SUN_CI, #sub "::" #name "_count");
+ 
+ void OptoRuntime::init_counters() {
+   assert(CompilerConfig::is_c2_enabled(), "");
+ 
+   if (UsePerfData) {
+     EXCEPTION_MARK;
+ 
+     DO_COUNTERS2(INIT_COUNTER_TIME_AND_CNT, INIT_COUNTER_CNT)
+ 
+     if (HAS_PENDING_EXCEPTION) {
+       vm_exit_during_initialization("jvm_perf_init failed unexpectedly");
+     }
+   }
+ }
+ #undef INIT_COUNTER_TIME_AND_CNT
+ #undef INIT_COUNTER_CNT
+ 
+ #define PRINT_COUNTER_TIME_AND_CNT(sub, name) { \
+   jlong count = _perf_##sub##_##name##_count->get_value(); \
+   if (count > 0) { \
+     st->print_cr("  %-50s = " JLONG_FORMAT_W(6) "us (elapsed) " JLONG_FORMAT_W(6) "us (thread) (" JLONG_FORMAT_W(5) " events)", #sub "::" #name, \
+                  _perf_##sub##_##name##_timer->elapsed_counter_value_us(), \
+                  _perf_##sub##_##name##_timer->thread_counter_value_us(), \
+                  count); \
+   }}
+ 
+ #define PRINT_COUNTER_CNT(sub, name) { \
+   jlong count = _perf_##sub##_##name##_count->get_value(); \
+   if (count > 0) { \
+     st->print_cr("  %-30s = " JLONG_FORMAT_W(5) " events", #name, count); \
+   }}
+ 
+ void OptoRuntime::print_counters_on(outputStream* st) {
+   if (UsePerfData && ProfileRuntimeCalls && CompilerConfig::is_c2_enabled()) {
+     DO_COUNTERS2(PRINT_COUNTER_TIME_AND_CNT, PRINT_COUNTER_CNT)
+   } else {
+     st->print_cr("  OptoRuntime: no info (%s is disabled)",
+                  (!CompilerConfig::is_c2_enabled() ? "C2" : (UsePerfData ? "ProfileRuntimeCalls" : "UsePerfData")));
+   }
+ }
+ 
+ #undef PRINT_COUNTER_TIME_AND_CNT
+ #undef PRINT_COUNTER_CNT
+ #undef DO_COUNTERS2
< prev index next >