< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page
@@ -23,10 +23,11 @@
   */
  
  #include "precompiled.hpp"
  #include "cds/archiveUtils.hpp"
  #include "cds/cdsConfig.hpp"
+ #include "cds/cdsEnumKlass.hpp"
  #include "cds/classListWriter.hpp"
  #include "cds/heapShared.hpp"
  #include "cds/metaspaceShared.hpp"
  #include "classfile/classFileParser.hpp"
  #include "classfile/classFileStream.hpp"

@@ -42,10 +43,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"

@@ -69,10 +71,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"

@@ -757,10 +760,101 @@
    } else {
      assert(is_initialized(), "sanity check");
    }
  }
  
+ static bool are_super_types_initialized(InstanceKlass* ik) {
+   InstanceKlass* s = ik->java_super();
+   if (s != nullptr && !s->is_initialized()) {
+     return false;
+   }
+ 
+   if (ik->has_nonstatic_concrete_methods()) {
+     // Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
+     // having a superinterface that declares, non-static, concrete methods
+     Array<InstanceKlass*>* interfaces = ik->local_interfaces();
+     int len = interfaces->length();
+     for (int i = 0; i < len; i++) {
+       InstanceKlass* intf = interfaces->at(i);
+       if (!intf->is_initialized()) {
+         return false;
+       }
+     }
+   }
+ 
+   return true;
+ }
+ 
+ static void log_class_init_start(outputStream* st, JavaThread* current, InstanceKlass* ik, int init_id) {
+   ResourceMark rm;
+   const char* info = "";
+   if (ik->has_preinitialized_mirror() && CDSConfig::is_loading_heap()) {
+     info = " (preinitialized)";
+   } else if (ik->class_initializer() == nullptr) {
+     info = " (no method)";
+   }
+   st->print("%d Initializing ", init_id);
+   ik->name()->print_value_on(st);
+   st->print_cr("%s (" PTR_FORMAT ") by thread " PTR_FORMAT " \"%s\"", info, p2i(ik), p2i(current), current->name());
+ }
+ 
+ static int log_class_init(JavaThread* current, InstanceKlass* ik) {
+   int init_id = -1;
+   LogStreamHandle(Info,  init, class) lsh1;
+   LogStreamHandle(Debug, init)        lsh2;
+   if (lsh1.is_enabled() || lsh2.is_enabled()) {
+     static int call_class_initializer_counter = 0;  // for debugging
+     init_id = Atomic::fetch_then_add(&call_class_initializer_counter, 1);
+     if (lsh1.is_enabled()) {
+       log_class_init_start(&lsh1, current, ik, init_id);
+     }
+     if (lsh2.is_enabled() && ik->class_initializer() != nullptr && !ik->has_preinitialized_mirror()) {
+       log_class_init_start(&lsh2, current, ik, init_id);
+     }
+   }
+   return init_id;
+ }
+ 
+ void InstanceKlass::initialize_from_cds(TRAPS) {
+   if (is_initialized()) {
+     return;
+   }
+ 
+   if (has_preinitialized_mirror() && CDSConfig::is_loading_heap() &&
+       !ForceProfiling &&
+       !RecordTraining &&
+       are_super_types_initialized(this)) {
+     // FIXME: also check for events listeners such as JVMTI, JFR, etc
+     if (log_is_enabled(Info, cds, init)) {
+       ResourceMark rm;
+       log_info(cds, init)("%s (quickest)", external_name());
+     }
+ 
+     link_class(CHECK);
+ 
+ #ifdef AZZERT
+     {
+       MonitorLocker ml(THREAD, _init_monitor);
+       assert(!initialized(), "sanity");
+       assert(!is_being_initialized(), "sanity");
+       assert(!is_in_error_state(), "sanity");
+     }
+ #endif
+ 
+     log_class_init(THREAD, this);
+     set_init_thread(THREAD);
+     set_initialization_state_and_notify(fully_initialized, CHECK);
+     return;
+   }
+ 
+   if (log_is_enabled(Info, cds, init)) {
+     ResourceMark rm;
+     log_info(cds, init)("%s%s", external_name(),
+                         (has_preinitialized_mirror() && CDSConfig::is_loading_heap()) ? " (quicker)" : "");
+   }
+   initialize(THREAD);
+ }
  
  bool InstanceKlass::verify_code(TRAPS) {
    // 1) Verify the bytecodes
    return Verifier::verify(this, should_verify_class(), THREAD);
  }

@@ -976,10 +1070,12 @@
  
  // 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) {
+   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));
  
      // Set up method entry points for compiler and interpreter    .

@@ -1084,10 +1180,25 @@
    bool wait = false;
    bool throw_error = 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
    {

@@ -1223,10 +1334,11 @@
  
    // Step 9
    if (!HAS_PENDING_EXCEPTION) {
      set_initialization_state_and_notify(fully_initialized, THREAD);
      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;

@@ -1253,11 +1365,10 @@
      }
    }
    DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);
  }
  
- 
  void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) {
    MonitorLocker ml(current, _init_monitor);
  
    if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) {
      DeoptimizationScope deopt_scope;

@@ -1512,11 +1623,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);
    }

@@ -1580,12 +1693,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;

@@ -1603,37 +1714,72 @@
  
  #if INCLUDE_CDS
    // This is needed to ensure the consistency of the archived heap objects.
    if (has_archived_enum_objs()) {
      assert(is_shared(), "must be");
-     bool initialized = HeapShared::initialize_enum_klass(this, CHECK);
+     bool initialized = CDSEnumKlass::initialize_enum_klass(this, CHECK);
      if (initialized) {
        return;
      }
+   } else if (has_preinitialized_mirror() && CDSConfig::is_loading_heap()) {
+     log_class_init(THREAD, this);
+     return;
    }
  #endif
  
    methodHandle h_method(THREAD, class_initializer());
    assert(!is_initialized(), "we cannot initialize twice");
+   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: %ldms); ",
+                 init_id, timer.seconds() * 1000.0, ClassLoader::class_init_time_ms());
+       if (CountBytecodes || CountBytecodesPerThread) {
+         log.print("executed %ld 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 Initializing ", call_class_initializer_counter++);
+     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());
-   }
-   if (h_method() != nullptr) {
-     JavaCallArguments args; // No arguments
-     JavaValue result(T_VOID);
-     JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
+     ls.print_cr("%s (" PTR_FORMAT ")", h_method() == nullptr ? "(no method)" : "", p2i(this));
    }
  }
  
- 
  void InstanceKlass::mask_for(const methodHandle& method, int bci,
    InterpreterOopMap* entry_for) {
    // Lazily create the _oop_map_cache at first request.
    // Load_acquire is needed to safely get instance published with CAS by another thread.
    OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache);

@@ -2390,11 +2536,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);
  }

@@ -2519,23 +2665,24 @@
          }
        }
      }
    }
  
+   it->push(&_nest_host);
    it->push(&_nest_members);
    it->push(&_permitted_subclasses);
    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,

@@ -2553,11 +2700,12 @@
    { // Otherwise this needs to take out the Compile_lock.
      assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
      init_implementor();
    }
  
-   constants()->remove_unshareable_info();
+   // ConstantPool is cleaned separately. See ArchiveBuilder::make_klasses_shareable()
+   // constants()->remove_unshareable_info();
  
    for (int i = 0; i < methods()->length(); i++) {
      Method* m = methods()->at(i);
      m->remove_unshareable_info();
    }

@@ -2580,15 +2728,20 @@
  
    _init_thread = nullptr;
    _methods_jmethod_ids = nullptr;
    _jni_ids = nullptr;
    _oop_map_cache = nullptr;
-   // clear _nest_host to ensure re-load at runtime
-   _nest_host = nullptr;
+   if (ArchiveInvokeDynamic && HeapShared::is_lambda_proxy_klass(this)) {
+     // keep _nest_host
+   } else {
+     // clear _nest_host to ensure re-load at runtime
+     _nest_host = nullptr;
+   }
    init_shared_package_entry();
    _dep_context_last_cleaned = 0;
    _init_monitor = nullptr;
+   DEBUG_ONLY(_shared_class_load_count = 0);
  
    remove_unshareable_flags();
  }
  
  void InstanceKlass::remove_unshareable_flags() {

@@ -2693,21 +2846,31 @@
  
    // restore the monitor
    _init_monitor = create_init_monitor("InstanceKlassInitMonitorRestored_lock");
  }
  
- // 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;
    }
+ 
+   if (ArchiveInvokeDynamic) {
+     // FIXME: this works around JDK-8315719
+     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;

@@ -2734,10 +2897,22 @@
        }
      }
    }
    return false;
  }
+ 
+ int InstanceKlass::shared_class_loader_type() const {
+   if (is_shared_boot_class()) {
+     return ClassLoader::BOOT_LOADER;
+   } else if (is_shared_platform_class()) {
+     return ClassLoader::PLATFORM_LOADER;
+   } else if (is_shared_app_class()) {
+     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();

@@ -3503,10 +3678,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();

@@ -3845,10 +4024,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 >