Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8275908: Record null_check traps for calls and array_check traps in the interpreter #6541

Closed
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -407,7 +407,11 @@ JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* current,
// lookup exception klass
TempNewSymbol s = SymbolTable::new_symbol(name);
if (ProfileTraps) {
note_trap(current, Deoptimization::Reason_class_check);
if (s == vmSymbols::java_lang_ArrayStoreException()) {
note_trap(current, Deoptimization::Reason_array_check);
} else {
note_trap(current, Deoptimization::Reason_class_check);
}
}
// create exception, with klass name as detail message
Handle exception = Exceptions::new_exception(current, s, klass_name);
@@ -825,7 +829,18 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt
JavaThread* THREAD = current; // For exception macros.
LinkResolver::resolve_invoke(info, receiver, pool,
last_frame.get_index_u2_cpcache(bytecode), bytecode,
CHECK);
THREAD);

if(HAS_PENDING_EXCEPTION) {
if (ProfileTraps && PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_NullPointerException()) {
// Preserve the original exception across the call to note_trap()
PreserveExceptionMark pm(current);
// Recording the trap will help the compiler to potentially recognize this exception as "hot"
note_trap(current, Deoptimization::Reason_null_check);
}
return;
}

if (JvmtiExport::can_hotswap_or_post_breakpoint() && info.resolved_method()->is_old()) {
resolved_method = methodHandle(current, info.resolved_method()->get_new_method());
} else {
@@ -580,11 +580,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
break;
case Deoptimization::Reason_class_check:
if (java_bc() == Bytecodes::_aastore) {
ex_obj = env()->ArrayStoreException_instance();
} else {
ex_obj = env()->ClassCastException_instance();
}
ex_obj = env()->ClassCastException_instance();
break;
case Deoptimization::Reason_array_check:
ex_obj = env()->ArrayStoreException_instance();
break;
default:
break;
@@ -3340,7 +3339,10 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
// It needs a null check because a null will *pass* the cast check.
// A non-null value will always produce an exception.
if (!objtp->maybe_null()) {
builtin_throw(Deoptimization::Reason_class_check, makecon(TypeKlassPtr::make(objtp->klass())));
bool aastore = (java_bc() == Bytecodes::_aastore);
simonis marked this conversation as resolved.
Show resolved Hide resolved
Deoptimization::DeoptReason reason = aastore ?
Deoptimization::Reason_array_check : Deoptimization::Reason_class_check;
builtin_throw(reason, makecon(TypeKlassPtr::make(objtp->klass())));
return top();
} else if (!too_many_traps_or_recompiles(Deoptimization::Reason_null_assert)) {
return null_assert(obj);
@@ -3422,7 +3424,10 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
if (not_subtype_ctrl != top()) { // If failure is possible
PreserveJVMState pjvms(this);
set_control(not_subtype_ctrl);
builtin_throw(Deoptimization::Reason_class_check, load_object_klass(not_null_obj));
bool aastore = (java_bc() == Bytecodes::_aastore);
Deoptimization::DeoptReason reason = aastore ?
Deoptimization::Reason_array_check : Deoptimization::Reason_class_check;
builtin_throw(reason, load_object_klass(not_null_obj));
}
} else {
(*failure_control) = not_subtype_ctrl;
@@ -298,4 +298,3 @@ void Parse::dump_map_adr_mem() const {
}

#endif

simonis marked this conversation as resolved.
Show resolved Hide resolved
@@ -955,6 +955,72 @@ WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method
}
WB_END

WB_ENTRY(jint, WB_GetMethodDecompileCount(JNIEnv* env, jobject o, jobject method))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, 0);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
uint cnt = 0;
MethodData* mdo = mh->method_data();
if (mdo != NULL) {
cnt = mdo->decompile_count();
}
return cnt;
WB_END

// Get the trap count of a method for a specific reason. If the trap count for
// that reason did overflow, this includes the overflow trap count of the method.
// If 'reason' is NULL, the sum of the traps for all reasons will be returned.
// This number includes the overflow trap count if the trap count for any reason
// did overflow.
WB_ENTRY(jint, WB_GetMethodTrapCount(JNIEnv* env, jobject o, jobject method, jstring reason_obj))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, 0);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
uint cnt = 0;
MethodData* mdo = mh->method_data();
if (mdo != NULL) {
ResourceMark rm(THREAD);
char* reason_str = (reason_obj == NULL) ?
NULL : java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(reason_obj));
bool overflow = false;
for (uint reason = 0; reason < mdo->trap_reason_limit(); reason++) {
if (reason_str != NULL && !strcmp(reason_str, Deoptimization::trap_reason_name(reason))) {
cnt = mdo->trap_count(reason);
// Count in the overflow trap count on overflow
if (cnt == (uint)-1) {
cnt = mdo->trap_count_limit() + mdo->overflow_trap_count();
}
break;
} else if (reason_str == NULL) {
uint c = mdo->trap_count(reason);
if (c == (uint)-1) {
c = mdo->trap_count_limit();
if (!overflow) {
// Count overflow trap count just once
overflow = true;
c += mdo->overflow_trap_count();
}
}
cnt += c;
}
}
}
return cnt;
WB_END

WB_ENTRY(jint, WB_GetDeoptCount(JNIEnv* env, jobject o, jstring reason_obj, jstring action_obj))
if (reason_obj == NULL && action_obj == NULL) {
return Deoptimization::total_deoptimization_count();
}
ResourceMark rm(THREAD);
const char *reason_str = (reason_obj == NULL) ?
NULL : java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(reason_obj));
const char *action_str = (action_obj == NULL) ?
NULL : java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(action_obj));

return Deoptimization::deoptimization_count(reason_str, action_str);
WB_END

WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, InvocationEntryBci);
@@ -2527,6 +2593,13 @@ static JNINativeMethod methods[] = {
CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod},
{CC"getMethodCompilationLevel0",
CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel},
{CC"getMethodDecompileCount0",
CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodDecompileCount},
{CC"getMethodTrapCount0",
CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I",
(void*)&WB_GetMethodTrapCount},
{CC"getDeoptCount0",
CC"(Ljava/lang/String;Ljava/lang/String;)I", (void*)&WB_GetDeoptCount},
{CC"getMethodEntryBci0",
CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci},
{CC"getCompileQueueSize",
@@ -2608,6 +2608,30 @@ jint Deoptimization::total_deoptimization_count() {
return _deoptimization_hist[Reason_none][0][0];
}

// Get the deopt count for a specific reason and a specific action. If either
// one of 'reason' or 'action' is null, the method returns the sum of all
// deoptimizations with the specific 'action' or 'reason' respectively.
// If both arguments are null, the method returns the total deopt count.
jint Deoptimization::deoptimization_count(const char *reason_str, const char *action_str) {
if (reason_str == NULL && action_str == NULL) {
return total_deoptimization_count();
}
juint counter = 0;
for (int reason = 0; reason < Reason_LIMIT; reason++) {
if (reason_str == NULL || !strcmp(reason_str, trap_reason_name(reason))) {
for (int action = 0; action < Action_LIMIT; action++) {
if (action_str == NULL || !strcmp(action_str, trap_action_name(action))) {
juint* cases = _deoptimization_hist[reason][1+action];
for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
counter += cases[bc_case] >> LSB_BITS;
}
}
}
}
}
return counter;
}

void Deoptimization::print_statistics() {
juint total = total_deoptimization_count();
juint account = total;
@@ -2661,6 +2685,14 @@ const char* Deoptimization::trap_reason_name(int reason) {
return "unknown";
}

jint Deoptimization::total_deoptimization_count() {
return 0;
}

jint Deoptimization::deoptimization_count(const char *reason_str, const char *action_str) {
return 0;
}

void Deoptimization::print_statistics() {
// no output
}
@@ -433,6 +433,7 @@ class Deoptimization : AllStatic {
int trap_request);

static jint total_deoptimization_count();
static jint deoptimization_count(const char *reason_str, const char *action_str);
simonis marked this conversation as resolved.
Show resolved Hide resolved

// JVMTI PopFrame support