mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8367002: Missing compiled exception handler for "recursive" exception
Reviewed-by: thartmann, kvn
This commit is contained in:
parent
2a8cbd944b
commit
0744db8366
@ -1804,10 +1804,11 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, DeoptReason reason
|
||||
deoptimize_single_frame(thread, fr, reason);
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) {
|
||||
address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm, bool make_not_entrant) {
|
||||
// there is no exception handler for this pc => deoptimize
|
||||
nm->make_not_entrant(nmethod::InvalidationReason::MISSING_EXCEPTION_HANDLER);
|
||||
if (make_not_entrant) {
|
||||
nm->make_not_entrant(nmethod::InvalidationReason::MISSING_EXCEPTION_HANDLER);
|
||||
}
|
||||
|
||||
// Use Deoptimization::deoptimize for all of its side-effects:
|
||||
// gathering traps statistics, logging...
|
||||
@ -1821,6 +1822,15 @@ address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) {
|
||||
frame runtime_frame = thread->last_frame();
|
||||
frame caller_frame = runtime_frame.sender(®_map);
|
||||
assert(caller_frame.cb()->as_nmethod_or_null() == nm, "expect top frame compiled method");
|
||||
|
||||
Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler);
|
||||
|
||||
if (!nm->is_compiled_by_jvmci()) {
|
||||
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
// JVMCI support
|
||||
vframe* vf = vframe::new_vframe(&caller_frame, ®_map, thread);
|
||||
compiledVFrame* cvf = compiledVFrame::cast(vf);
|
||||
ScopeDesc* imm_scope = cvf->scope();
|
||||
@ -1836,16 +1846,15 @@ address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) {
|
||||
}
|
||||
}
|
||||
|
||||
Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler);
|
||||
|
||||
MethodData* trap_mdo = get_method_data(thread, methodHandle(thread, nm->method()), true);
|
||||
if (trap_mdo != nullptr) {
|
||||
trap_mdo->inc_trap_count(Deoptimization::Reason_not_compiled_exception_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) {
|
||||
assert(thread == Thread::current() ||
|
||||
@ -2748,10 +2757,10 @@ const char* Deoptimization::_trap_reason_name[] = {
|
||||
"unstable_if",
|
||||
"unstable_fused_if",
|
||||
"receiver_constraint",
|
||||
"not_compiled_exception_handler",
|
||||
"short_running_loop" JVMCI_ONLY("_or_aliasing"),
|
||||
#if INCLUDE_JVMCI
|
||||
"transfer_to_interpreter",
|
||||
"not_compiled_exception_handler",
|
||||
"unresolved",
|
||||
"jsr_mismatch",
|
||||
#endif
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -117,11 +117,11 @@ class Deoptimization : AllStatic {
|
||||
Reason_unstable_if, // a branch predicted always false was taken
|
||||
Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken.
|
||||
Reason_receiver_constraint, // receiver subtype check failed
|
||||
Reason_not_compiled_exception_handler, // missing compiled exception handler
|
||||
Reason_short_running_long_loop, // profile reports loop runs for small number of iterations
|
||||
#if INCLUDE_JVMCI
|
||||
Reason_aliasing = Reason_short_running_long_loop, // optimistic assumption about aliasing failed
|
||||
Reason_transfer_to_interpreter, // explicit transferToInterpreter()
|
||||
Reason_not_compiled_exception_handler,
|
||||
Reason_unresolved,
|
||||
Reason_jsr_mismatch,
|
||||
#endif
|
||||
@ -184,8 +184,8 @@ class Deoptimization : AllStatic {
|
||||
// Deoptimizes a frame lazily. Deopt happens on return to the frame.
|
||||
static void deoptimize(JavaThread* thread, frame fr, DeoptReason reason = Reason_constraint);
|
||||
|
||||
static address deoptimize_for_missing_exception_handler(nmethod* nm, bool make_not_entrant);
|
||||
#if INCLUDE_JVMCI
|
||||
static address deoptimize_for_missing_exception_handler(nmethod* nm);
|
||||
static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, bool& cache_init_error, TRAPS);
|
||||
#endif
|
||||
|
||||
|
||||
@ -791,7 +791,8 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc,
|
||||
if (t != nullptr) {
|
||||
return nm->code_begin() + t->pco();
|
||||
} else {
|
||||
return Deoptimization::deoptimize_for_missing_exception_handler(nm);
|
||||
bool make_not_entrant = true;
|
||||
return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JVMCI
|
||||
@ -847,6 +848,15 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc,
|
||||
|
||||
ExceptionHandlerTable table(nm);
|
||||
HandlerTableEntry *t = table.entry_for(catch_pco, handler_bci, scope_depth);
|
||||
|
||||
// If the compiler did not anticipate a recursive exception, resulting in an exception
|
||||
// thrown from the catch bci, then the compiled exception handler might be missing.
|
||||
// This is rare. Just deoptimize and let the interpreter handle it.
|
||||
if (t == nullptr && recursive_exception_occurred) {
|
||||
bool make_not_entrant = false;
|
||||
return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant);
|
||||
}
|
||||
|
||||
if (t == nullptr && (nm->is_compiled_by_c1() || handler_bci != -1)) {
|
||||
// Allow abbreviated catch tables. The idea is to allow a method
|
||||
// to materialize its exceptions without committing to the exact
|
||||
|
||||
@ -1581,8 +1581,8 @@
|
||||
declare_constant(Deoptimization::Reason_unstable_if) \
|
||||
declare_constant(Deoptimization::Reason_unstable_fused_if) \
|
||||
declare_constant(Deoptimization::Reason_receiver_constraint) \
|
||||
declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \
|
||||
NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_transfer_to_interpreter))) \
|
||||
NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_not_compiled_exception_handler))) \
|
||||
NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_unresolved))) \
|
||||
NOT_ZERO(JVMCI_ONLY(declare_constant(Deoptimization::Reason_jsr_mismatch))) \
|
||||
declare_constant(Deoptimization::Reason_tenured) \
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
super class IllegalAccessInCatch
|
||||
version 52:0
|
||||
{
|
||||
/*
|
||||
static int test() {
|
||||
try {
|
||||
return 1 / 0;
|
||||
} catch (jdk.internal.agent.AgentConfigurationError e1) {
|
||||
try {
|
||||
return 0;
|
||||
} catch (IllegalAccessError e2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
static Method test:"()I"
|
||||
stack 2 locals 1
|
||||
{
|
||||
iconst_1;
|
||||
iconst_0;
|
||||
try t0;
|
||||
idiv;
|
||||
endtry t0;
|
||||
ireturn;
|
||||
catch t0 jdk/internal/agent/AgentConfigurationError; // loadable but not accessible from unnamed module
|
||||
stack_frame_type full;
|
||||
stack_map class java/lang/Throwable;
|
||||
try t1;
|
||||
iconst_0;
|
||||
ireturn;
|
||||
endtry t1;
|
||||
catch t1 java/lang/IllegalAccessError;
|
||||
stack_frame_type full;
|
||||
stack_map class java/lang/Throwable;
|
||||
iconst_1;
|
||||
ireturn;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8367002
|
||||
* @summary Compilers might not generate handlers for recursive exceptions
|
||||
*
|
||||
* @compile IllegalAccessInCatch.jasm
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test
|
||||
* -XX:-TieredCompilation
|
||||
* TestAccessErrorInCatch
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileCommand=compileonly,IllegalAccessInCatch*::test
|
||||
* -XX:TieredStopAtLevel=3
|
||||
* TestAccessErrorInCatch
|
||||
*/
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class TestAccessErrorInCatch {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Path TEST_CLASSES_DIR = FileSystems.getDefault().getPath(System.getProperty("test.classes"));
|
||||
byte[] bytes = Files.readAllBytes(TEST_CLASSES_DIR.resolve("IllegalAccessInCatch.class"));
|
||||
|
||||
var l = MethodHandles.lookup().defineHiddenClass(bytes, true);
|
||||
Class<?> anonClass = l.lookupClass();
|
||||
MethodHandle mh = l.findStatic(anonClass, "test", MethodType.methodType(int.class));
|
||||
for (int i = 0; i < 16_000; i++) {
|
||||
invoke(mh);
|
||||
}
|
||||
System.out.println(invoke(mh));
|
||||
}
|
||||
|
||||
private static int invoke(MethodHandle mh) throws Throwable {
|
||||
return (int) mh.invokeExact();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user