< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page
@@ -44,10 +44,11 @@
  #include "code/codeCache.hpp"
  #include "code/dependencyContext.hpp"
  #include "compiler/compilationPolicy.hpp"
  #include "compiler/compileBroker.hpp"
  #include "gc/shared/collectedHeap.inline.hpp"
+ #include "interpreter/bytecodeHistogram.hpp"
  #include "interpreter/bytecodeStream.hpp"
  #include "interpreter/oopMapCache.hpp"
  #include "interpreter/rewriter.hpp"
  #include "jvm.h"
  #include "jvmtifiles/jvmti.h"

@@ -72,10 +73,11 @@
  #include "oops/klass.inline.hpp"
  #include "oops/method.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/recordComponent.hpp"
  #include "oops/symbol.hpp"
+ #include "oops/trainingData.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/jvmtiRedefineClasses.hpp"
  #include "prims/jvmtiThreadState.hpp"
  #include "prims/methodComparator.hpp"
  #include "runtime/arguments.hpp"

@@ -87,10 +89,11 @@
  #include "runtime/javaThread.inline.hpp"
  #include "runtime/mutexLocker.hpp"
  #include "runtime/orderAccess.hpp"
  #include "runtime/os.inline.hpp"
  #include "runtime/reflection.hpp"
+ #include "runtime/runtimeUpcalls.hpp"
  #include "runtime/synchronizer.hpp"
  #include "runtime/threads.hpp"
  #include "services/classLoadingService.hpp"
  #include "services/finalizerService.hpp"
  #include "services/threadService.hpp"

@@ -1055,15 +1058,16 @@
  
  // Now relocate and link method entry points after class is rewritten.
  // This is outside is_rewritten flag. In case of an exception, it can be
  // executed more than once.
  void InstanceKlass::link_methods(TRAPS) {
-   PerfTraceTime timer(ClassLoader::perf_ik_link_methods_time());
+   PerfTraceElapsedTime timer(ClassLoader::perf_ik_link_methods_time());
  
    int len = methods()->length();
    for (int i = len-1; i >= 0; i--) {
      methodHandle m(THREAD, methods()->at(i));
+     RuntimeUpcalls::install_upcalls(m);
  
      // Set up method entry points for compiler and interpreter    .
      m->link_method(m, CHECK);
    }
  }

@@ -1164,10 +1168,25 @@
  
    bool wait = false;
  
    JavaThread* jt = THREAD;
  
+   if (ForceProfiling) {
+     // Preallocate MDOs.
+     for (int i = 0; i < methods()->length(); i++) {
+       assert(!HAS_PENDING_EXCEPTION, "");
+       methodHandle m(THREAD, methods()->at(i));
+       Method::build_profiling_method_data(m, THREAD);
+       if (HAS_PENDING_EXCEPTION) {
+         ResourceMark rm;
+         log_warning(cds)("MDO preallocation failed for %s", external_name());
+         CLEAR_PENDING_EXCEPTION;
+         break;
+       }
+     }
+   }
+ 
    bool debug_logging_enabled = log_is_enabled(Debug, class, init);
  
    // refer to the JVM book page 47 for description of steps
    // Step 1
    {

@@ -1302,10 +1321,11 @@
  
    // Step 9
    if (!HAS_PENDING_EXCEPTION) {
      set_initialization_state_and_notify(fully_initialized, CHECK);
      debug_only(vtable().verify(tty, true);)
+     CompilationPolicy::replay_training_at_init(this, THREAD);
    }
    else {
      // Step 10 and 11
      Handle e(THREAD, PENDING_EXCEPTION);
      CLEAR_PENDING_EXCEPTION;

@@ -1332,11 +1352,10 @@
      }
    }
    DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);
  }
  
- 
  void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) {
    Handle h_init_lock(THREAD, init_lock());
    if (h_init_lock() != nullptr) {
      ObjectLocker ol(h_init_lock, THREAD);
      set_init_thread(nullptr); // reset _init_thread before changing _init_state

@@ -1562,11 +1581,13 @@
    assert(!is_abstract() && !is_interface(), "Should not create this object");
    size_t size = size_helper();  // Query before forming handle.
    return (instanceOop)Universe::heap()->obj_allocate(this, size, CHECK_NULL);
  }
  
- instanceOop InstanceKlass::allocate_instance(oop java_class, TRAPS) {
+ instanceOop InstanceKlass::allocate_instance(oop java_class,
+                                              const char* who,
+                                              TRAPS) {
    Klass* k = java_lang_Class::as_Klass(java_class);
    if (k == nullptr) {
      ResourceMark rm(THREAD);
      THROW_(vmSymbols::java_lang_InstantiationException(), nullptr);
    }

@@ -1630,12 +1651,10 @@
  
  ArrayKlass* InstanceKlass::array_klass_or_null() {
    return array_klass_or_null(1);
  }
  
- static int call_class_initializer_counter = 0;   // for debugging
- 
  Method* InstanceKlass::class_initializer() const {
    Method* clinit = find_method(
        vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
    if (clinit != nullptr && clinit->has_valid_initializer_flags()) {
      return clinit;

@@ -1665,10 +1684,65 @@
    }
  #endif
  
    methodHandle h_method(THREAD, class_initializer());
    assert(!is_initialized(), "we cannot initialize twice");
+ 
+ #if 0
+   // FIXME -- revive this code added to leyden/premain for <clinit> profiling
+   int init_id = log_class_init(THREAD, this);
+   if (h_method() != nullptr) {
+     JavaCallArguments args; // No arguments
+     JavaValue result(T_VOID);
+     InstanceKlass* outer = THREAD->set_class_being_initialized(this);
+     jlong bc_start = (CountBytecodesPerThread ? THREAD->bc_counter_value() : BytecodeCounter::counter_value());
+ 
+     elapsedTimer timer;
+     {
+       PerfPauseTimer pt(THREAD->current_rt_call_timer(), THREAD->profile_rt_calls());
+       PauseRuntimeCallProfiling prcp(THREAD, THREAD->profile_rt_calls());
+ 
+       timer.start();
+       JavaCalls::call(&result, h_method, &args, THREAD); // Static call (no args)
+       timer.stop();
+     }
+ 
+     jlong bc_end = (CountBytecodesPerThread ? THREAD->bc_counter_value() : BytecodeCounter::counter_value());
+ 
+     jlong bc_executed = (bc_end - bc_start);
+     if (UsePerfData && outer == nullptr) { // outermost clinit
+       THREAD->inc_clinit_bc_counter_value(bc_executed);
+       ClassLoader::perf_class_init_bytecodes_count()->inc(bc_executed);
+     }
+ 
+     THREAD->set_class_being_initialized(outer);
+ 
+     LogStreamHandle(Debug, init) log;
+     if (log.is_enabled()) {
+       ResourceMark rm(THREAD);
+       log.print("%d Initialized in %.3fms (total: " JLONG_FORMAT "ms); ",
+                 init_id, timer.seconds() * 1000.0, ClassLoader::class_init_time_ms());
+       if (CountBytecodes || CountBytecodesPerThread) {
+         log.print("executed " JLONG_FORMAT " bytecodes; ", bc_executed);
+       }
+       name()->print_value_on(&log);
+       log.print_cr(" by thread " PTR_FORMAT " \"%s\" (" PTR_FORMAT ")",
+                    p2i(THREAD), THREAD->name(), p2i(this));
+     }
+   }
+   LogTarget(Info, class, init) lt;
+   if (lt.is_enabled()) {
+     ResourceMark rm(THREAD);
+     LogStream ls(lt);
+     ls.print("%d Initialized ", init_id);
+     name()->print_value_on(&ls);
+     ls.print_cr("%s (" PTR_FORMAT ") by thread \"%s\"",
+                 h_method() == nullptr ? "(no method)" : "", p2i(this),
+                 THREAD->name());
+   }
+ #else
+   static int call_class_initializer_counter = 0;   // for debugging
    LogTarget(Info, class, init) lt;
    if (lt.is_enabled()) {
      ResourceMark rm(THREAD);
      LogStream ls(lt);
      ls.print("%d Initializing ", call_class_initializer_counter++);

@@ -1681,10 +1755,11 @@
      ThreadInClassInitializer ticl(THREAD, this); // Track class being initialized
      JavaCallArguments args; // No arguments
      JavaValue result(T_VOID);
      JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
    }
+ #endif
  }
  
  // If a class that implements this interface is initialized, is the JVM required
  // to first execute a <clinit> method declared in this interface,
  // or (if also_check_supers==true) any of the super types of this interface?

@@ -2485,11 +2560,11 @@
    DependencyContext dep_context(&_dep_context, &_dep_context_last_cleaned);
    return dep_context;
  }
  
  void InstanceKlass::mark_dependent_nmethods(DeoptimizationScope* deopt_scope, KlassDepChange& changes) {
-   dependencies().mark_dependent_nmethods(deopt_scope, changes);
+   dependencies().mark_dependent_nmethods(deopt_scope, changes, this);
  }
  
  void InstanceKlass::add_dependent_nmethod(nmethod* nm) {
    dependencies().add_dependent_nmethod(nm);
  }

@@ -2622,16 +2697,16 @@
    it->push(&_record_components);
  }
  
  #if INCLUDE_CDS
  void InstanceKlass::remove_unshareable_info() {
- 
    if (is_linked()) {
      assert(can_be_verified_at_dumptime(), "must be");
      // Remember this so we can avoid walking the hierarchy at runtime.
      set_verified_at_dump_time();
    }
+   _misc_flags.set_has_init_deps_processed(false);
  
    Klass::remove_unshareable_info();
  
    if (SystemDictionaryShared::has_class_failed_verification(this)) {
      // Classes are attempted to link during dumping and may fail,

@@ -2686,10 +2761,11 @@
      // clear _nest_host to ensure re-load at runtime
      _nest_host = nullptr;
    }
    init_shared_package_entry();
    _dep_context_last_cleaned = 0;
+   DEBUG_ONLY(_shared_class_load_count = 0);
  
    remove_unshareable_flags();
  }
  
  void InstanceKlass::remove_unshareable_flags() {

@@ -2796,21 +2872,26 @@
    if (DiagnoseSyncOnValueBasedClasses && has_value_based_class_annotation() && !is_value_based()) {
      set_is_value_based();
    }
  }
  
- // Check if a class or any of its supertypes has a version older than 50.
- // CDS will not perform verification of old classes during dump time because
- // without changing the old verifier, the verification constraint cannot be
- // retrieved during dump time.
- // Verification of archived old classes will be performed during run time.
  bool InstanceKlass::can_be_verified_at_dumptime() const {
+   if (CDSConfig::preserve_all_dumptime_verification_states(this)) {
+     return true;
+   }
+ 
    if (MetaspaceShared::is_in_shared_metaspace(this)) {
      // This is a class that was dumped into the base archive, so we know
      // it was verified at dump time.
      return true;
    }
+ 
+   // Check if a class or any of its supertypes has a version older than 50.
+   // CDS will not perform verification of old classes during dump time because
+   // without changing the old verifier, the verification constraint cannot be
+   // retrieved during dump time.
+   // Verification of archived old classes will be performed during run time.
    if (major_version() < 50 /*JAVA_6_VERSION*/) {
      return false;
    }
    if (java_super() != nullptr && !java_super()->can_be_verified_at_dumptime()) {
      return false;

@@ -2834,10 +2915,11 @@
      return ClassLoader::APP_LOADER;
    } else {
      return ClassLoader::OTHER;
    }
  }
+ 
  #endif // INCLUDE_CDS
  
  #if INCLUDE_JVMTI
  static void clear_all_breakpoints(Method* m) {
    m->clear_all_breakpoints();

@@ -3611,10 +3693,14 @@
  
  const char* InstanceKlass::init_state_name() const {
    return state_names[init_state()];
  }
  
+ const char* InstanceKlass::state2name(ClassState s) {
+   return state_names[s];
+ }
+ 
  void InstanceKlass::print_on(outputStream* st) const {
    assert(is_klass(), "must be klass");
    Klass::print_on(st);
  
    st->print(BULLET"instance size:     %d", size_helper());                        st->cr();

@@ -3940,10 +4026,27 @@
      } else {
        info_stream.print(" source: shared objects file");
      }
    }
  
+   info_stream.print(" loader:");
+   if (is_shared()) {
+     info_stream.print(" %s", SystemDictionaryShared::class_loader_name_for_shared((Klass*)this));
+   } else if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
+     info_stream.print(" boot_loader");
+   } else {
+     oop class_loader = loader_data->class_loader();
+     if (class_loader != nullptr) {
+       info_stream.print(" %s", class_loader->klass()->external_name());
+       oop cl_name_and_id = java_lang_ClassLoader::nameAndId(class_loader);
+       if (cl_name_and_id != nullptr) {
+         info_stream.print(" %s", java_lang_String::as_utf8_string(cl_name_and_id));
+       }
+     } else {
+       info_stream.print(" null");
+     }
+   }
    msg.info("%s", info_stream.as_string());
  
    if (log_is_enabled(Debug, class, load)) {
      stringStream debug_stream;
  
< prev index next >