< prev index next > src/hotspot/share/ci/ciMethod.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
+ #include "cds/aotLinkedClassBulkLoader.hpp"
#include "ci/ciCallProfile.hpp"
#include "ci/ciExceptionHandler.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodBlocks.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciSymbols.hpp"
#include "ci/ciUtilities.inline.hpp"
+ #include "compiler/compileTask.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compilerDefinitions.inline.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/methodLiveness.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/generateOopMap.hpp"
#include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp"
+ #include "oops/trainingData.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/xmlstream.hpp"
_name = env->get_symbol(h_m->name());
ciSymbol* sig_symbol = env->get_symbol(h_m->signature());
constantPoolHandle cpool(Thread::current(), h_m->constants());
_signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
_method_data = nullptr;
+ _method_data_recorded = nullptr;
// Take a snapshot of these values, so they will be commensurate with the MDO.
if (ProfileInterpreter || CompilerConfig::is_c1_profiling()) {
int invcnt = h_m->interpreter_invocation_count();
// if the value overflowed report it as max int
_interpreter_invocation_count = invcnt < 0 ? max_jint : invcnt ;
_interpreter_invocation_count = 1;
_inline_instructions_size = -1;
if (ReplayCompiles) {
ciReplay::initialize(this);
}
+ DirectiveSet* directives = DirectivesStack::getMatchingDirective(h_m, CURRENT_ENV->task()->compiler());
+ ccstrlist bci_list = directives->TooManyTrapsAtBCIOption;
+ int len = (int)strlen(bci_list);
+ Arena* arena = CURRENT_ENV->arena();
+ _has_trap_at_bci = new (arena) GrowableArray<int>(arena, 2, 0, 0);
+ for (int i = 0; i < len; i++) {
+ int v = -1;
+ int read;
+ if (sscanf(bci_list + i, "%i%n", &v, &read) != 1) {
+ warning("wrong format for TooManyTrapsAtBCI option: \"%s\"", bci_list);
+ break;
+ }
+ assert(v >= 0 && v < (1<<16), "%i", v);
+ _has_trap_at_bci->append_if_missing(v);
+ i += read;
+ }
}
// ------------------------------------------------------------------
// ciMethod::ciMethod
ciInstanceKlass* accessor) :
ciMetadata((Metadata*)nullptr),
_name( name),
_holder( holder),
_method_data( nullptr),
+ _method_data_recorded( nullptr),
_method_blocks( nullptr),
_intrinsic_id( vmIntrinsics::_none),
_inline_instructions_size(-1),
_can_be_statically_bound(false),
_can_omit_stack_trace(true),
+ _has_trap_at_bci( nullptr),
_liveness( nullptr)
#if defined(COMPILER2)
,
_flow( nullptr),
_bcea( nullptr)
// ------------------------------------------------------------------
// ciMethod::ensure_method_data
//
// Generate new MethodData* objects at compile time.
// Return true if allocation was successful or no MDO is required.
! bool ciMethod::ensure_method_data(const methodHandle& h_m) {
EXCEPTION_CONTEXT;
if (is_native() || is_abstract() || h_m()->is_accessor()) {
return true;
}
if (h_m()->method_data() == nullptr) {
! Method::build_profiling_method_data(h_m, THREAD);
! if (HAS_PENDING_EXCEPTION) {
! CLEAR_PENDING_EXCEPTION;
}
}
if (h_m()->method_data() != nullptr) {
_method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
return _method_data->load_data();
// ------------------------------------------------------------------
// ciMethod::ensure_method_data
//
// Generate new MethodData* objects at compile time.
// Return true if allocation was successful or no MDO is required.
! bool ciMethod::ensure_method_data(const methodHandle& h_m, bool training_data_only) {
EXCEPTION_CONTEXT;
if (is_native() || is_abstract() || h_m()->is_accessor()) {
return true;
}
if (h_m()->method_data() == nullptr) {
! if (training_data_only) {
! Method::install_training_method_data(h_m);
! } else {
+ Method::build_profiling_method_data(h_m, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ }
}
}
if (h_m()->method_data() != nullptr) {
_method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
return _method_data->load_data();
return false;
}
}
// public, retroactive version
! bool ciMethod::ensure_method_data() {
bool result = true;
if (_method_data == nullptr || _method_data->is_empty()) {
GUARDED_VM_ENTRY({
methodHandle mh(Thread::current(), get_Method());
! result = ensure_method_data(mh);
});
}
return result;
}
// ------------------------------------------------------------------
// ciMethod::method_data
//
ciMethodData* ciMethod::method_data() {
! if (_method_data != nullptr) {
! return _method_data;
! }
! VM_ENTRY_MARK;
! ciEnv* env = CURRENT_ENV;
! Thread* my_thread = JavaThread::current();
! methodHandle h_m(my_thread, get_Method());
!
! if (h_m()->method_data() != nullptr) {
! _method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
! _method_data->load_data();
} else {
! _method_data = CURRENT_ENV->get_empty_methodData();
}
- return _method_data;
-
}
// ------------------------------------------------------------------
// ciMethod::method_data_or_null
// Returns a pointer to ciMethodData if MDO exists on the VM side,
return false;
}
}
// public, retroactive version
! bool ciMethod::ensure_method_data(bool training_data_only) {
bool result = true;
if (_method_data == nullptr || _method_data->is_empty()) {
GUARDED_VM_ENTRY({
methodHandle mh(Thread::current(), get_Method());
! result = ensure_method_data(mh, training_data_only);
});
}
return result;
}
// ------------------------------------------------------------------
// ciMethod::method_data
//
ciMethodData* ciMethod::method_data() {
! if (CURRENT_ENV->task()->is_precompiled() && CURRENT_ENV->task()->comp_level() == CompLevel_full_optimization) {
! if (_method_data_recorded == nullptr) {
! VM_ENTRY_MARK;
! methodHandle h_m(thread, get_Method());
! MethodTrainingData* mtd = TrainingData::lookup_for(h_m());
! MethodData* mdo = (mtd != nullptr ? mtd->final_profile() : nullptr);
! DirectiveSet* directives = DirectivesStack::getMatchingDirective(h_m, CURRENT_ENV->task()->compiler());
! if (mdo == nullptr || directives->IgnoreRecordedProfileOption) {
! if (directives->IgnoreRecordedProfileOption) {
! ResourceMark rm;
! log_debug(precompile)("Ignore recorded profile for %s", h_m->name_and_sig_as_C_string());
+ } else {
+ ResourceMark rm;
+ log_debug(precompile)("No profile for %s", h_m->name_and_sig_as_C_string());
+ }
+ _method_data_recorded = CURRENT_ENV->get_empty_methodData();
+ } else {
+ #if INCLUDE_CDS
+ if (mdo->extra_data_lock() == nullptr) {
+ assert(!HAS_PENDING_EXCEPTION, "");
+ mdo->restore_unshareable_info(thread);
+ assert(!HAS_PENDING_EXCEPTION, "");
+ }
+ #endif
+ _method_data_recorded = CURRENT_ENV->get_method_data(mdo);
+ _method_data_recorded->load_data();
+ {
+ ResourceMark rm;
+ log_debug(precompile)("Recorded profile " PTR_FORMAT " for %s", p2i(mdo), h_m->name_and_sig_as_C_string());
+ }
+ }
+ }
+ assert(_method_data_recorded != nullptr, "");
+ return _method_data_recorded;
} else {
! if (_method_data != nullptr) {
+ return _method_data;
+ }
+ VM_ENTRY_MARK;
+ methodHandle h_m(thread, get_Method());
+ MethodData* mdo = h_m()->method_data();
+ if (mdo != nullptr) {
+ _method_data = CURRENT_ENV->get_method_data(mdo);
+ _method_data->load_data();
+ } else {
+ _method_data = CURRENT_ENV->get_empty_methodData();
+ }
+ return _method_data;
}
}
// ------------------------------------------------------------------
// ciMethod::method_data_or_null
// Returns a pointer to ciMethodData if MDO exists on the VM side,
check_is_loaded();
ciEnv* env = CURRENT_ENV;
if (is_c1_compile(env->comp_level())) {
return _is_c1_compilable;
}
+
+ #if INCLUDE_JVMCI
+ if (EnableJVMCI && UseJVMCICompiler &&
+ env->comp_level() == CompLevel_full_optimization && !AOTLinkedClassBulkLoader::class_preloading_finished()) {
+ return false;
+ }
+ #endif
return _is_c2_compilable;
}
// ------------------------------------------------------------------
// ciMethod::has_compiled_code
// not highly relevant to an inlined method. So we use the more
// specific accessor nmethod::insts_size.
// Also some instructions inside the code are excluded from inline
// heuristic (e.g. post call nop instructions; see InlineSkippedInstructionsCounter)
int ciMethod::inline_instructions_size() {
if (_inline_instructions_size == -1) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
! if (code != nullptr && (code->comp_level() == CompLevel_full_optimization)) {
int isize = code->insts_end() - code->verified_entry_point() - code->skipped_instructions_size();
_inline_instructions_size = isize > 0 ? isize : 0;
} else {
_inline_instructions_size = 0;
}
);
}
return _inline_instructions_size;
}
// not highly relevant to an inlined method. So we use the more
// specific accessor nmethod::insts_size.
// Also some instructions inside the code are excluded from inline
// heuristic (e.g. post call nop instructions; see InlineSkippedInstructionsCounter)
int ciMethod::inline_instructions_size() {
+ if (_inline_instructions_size == -1) {
+ if (TrainingData::have_data()) {
+ GUARDED_VM_ENTRY(
+ CompLevel level = static_cast<CompLevel>(CURRENT_ENV->comp_level());
+ methodHandle top_level_mh(Thread::current(), CURRENT_ENV->task()->method());
+ MethodTrainingData* mtd = MethodTrainingData::find(top_level_mh);
+ if (mtd != nullptr) {
+ CompileTrainingData* ctd = mtd->last_toplevel_compile(level);
+ if (ctd != nullptr) {
+ methodHandle mh(Thread::current(), get_Method());
+ MethodTrainingData* this_mtd = MethodTrainingData::find(mh);
+ if (this_mtd != nullptr) {
+ auto r = ctd->ci_records().ciMethod__inline_instructions_size.find(this_mtd);
+ if (r.is_valid()) {
+ _inline_instructions_size = r.result();
+ }
+ }
+ }
+ }
+ );
+ }
+ }
if (_inline_instructions_size == -1) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
! if (code != nullptr && !code->is_scc() && (code->comp_level() == CompLevel_full_optimization)) {
int isize = code->insts_end() - code->verified_entry_point() - code->skipped_instructions_size();
_inline_instructions_size = isize > 0 ? isize : 0;
} else {
_inline_instructions_size = 0;
}
+ if (TrainingData::need_data()) {
+ CompileTrainingData* ctd = CURRENT_ENV->task()->training_data();
+ if (ctd != nullptr) {
+ methodHandle mh(Thread::current(), get_Method());
+ MethodTrainingData* this_mtd = MethodTrainingData::make(mh);
+ ctd->ci_records().ciMethod__inline_instructions_size.append_if_missing(_inline_instructions_size, this_mtd);
+ }
+ }
);
}
return _inline_instructions_size;
}
}
// ------------------------------------------------------------------
// ciMethod::was_never_executed
bool ciMethod::was_executed_more_than(int times) {
+ // Invocation counter is reset when the Method* is compiled.
+ // If the method has compiled code we therefore assume it has
+ // be executed more than n times.
+ if (is_accessor() || is_empty() || has_compiled_code()) {
+ // interpreter doesn't bump invocation counter of trivial methods
+ // compiler does not bump invocation counter of compiled methods
+ return true;
+ }
+ if (!method_data()->is_empty()) {
+ return (method_data()->invocation_count() > times);
+ }
VM_ENTRY_MARK;
return get_Method()->was_executed_more_than(times);
}
// ------------------------------------------------------------------
< prev index next >