Skip to content
Permalink
Browse files
8275908: Record null_check traps for calls and array_check traps in t…
…he interpreter

Reviewed-by: chagedorn, mdoerr
  • Loading branch information
simonis committed Nov 26, 2021
1 parent 3d810ad commit 40fef2311c95eca0ec34652f9fc0e56b827b8380
Showing 9 changed files with 636 additions and 9 deletions.
@@ -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 is_aastore = (java_bc() == Bytecodes::_aastore);
Deoptimization::DeoptReason reason = is_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 is_aastore = (java_bc() == Bytecodes::_aastore);
Deoptimization::DeoptReason reason = is_aastore ?
Deoptimization::Reason_array_check : Deoptimization::Reason_class_check;
builtin_throw(reason, load_object_klass(not_null_obj));
}
} else {
(*failure_control) = not_subtype_ctrl;
@@ -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);

// JVMTI PopFrame support

1 comment on commit 40fef23

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 40fef23 Nov 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.