8227260: JNI upcalls should bypass class initialization barrier in c2i adapter
Reviewed-by: eosterlund, dholmes, mdoerr
This commit is contained in:
parent
78c7364c17
commit
32eb2e45b6
@ -1277,6 +1277,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
c2i_entry = __ pc();
|
c2i_entry = __ pc();
|
||||||
|
|
||||||
// Class initialization barrier for static methods
|
// Class initialization barrier for static methods
|
||||||
|
address c2i_no_clinit_check_entry = NULL;
|
||||||
if (VM_Version::supports_fast_class_init_checks()) {
|
if (VM_Version::supports_fast_class_init_checks()) {
|
||||||
Label L_skip_barrier;
|
Label L_skip_barrier;
|
||||||
|
|
||||||
@ -1295,11 +1296,12 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
__ bctr();
|
__ bctr();
|
||||||
|
|
||||||
__ bind(L_skip_barrier);
|
__ bind(L_skip_barrier);
|
||||||
|
c2i_no_clinit_check_entry = __ pc();
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
|
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
|
||||||
|
|
||||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef COMPILER2
|
#ifdef COMPILER2
|
||||||
|
@ -2713,6 +2713,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
address c2i_entry = __ pc();
|
address c2i_entry = __ pc();
|
||||||
|
|
||||||
// Class initialization barrier for static methods
|
// Class initialization barrier for static methods
|
||||||
|
address c2i_no_clinit_check_entry = NULL;
|
||||||
if (VM_Version::supports_fast_class_init_checks()) {
|
if (VM_Version::supports_fast_class_init_checks()) {
|
||||||
Label L_skip_barrier;
|
Label L_skip_barrier;
|
||||||
|
|
||||||
@ -2729,11 +2730,12 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
__ z_br(klass);
|
__ z_br(klass);
|
||||||
|
|
||||||
__ bind(L_skip_barrier);
|
__ bind(L_skip_barrier);
|
||||||
|
c2i_no_clinit_check_entry = __ pc();
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||||
|
|
||||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function returns the adjust size (in number of words) to a c2i adapter
|
// This function returns the adjust size (in number of words) to a c2i adapter
|
||||||
|
@ -971,10 +971,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
|
|
||||||
address c2i_entry = __ pc();
|
address c2i_entry = __ pc();
|
||||||
|
|
||||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
|
||||||
bs->c2i_entry_barrier(masm);
|
|
||||||
|
|
||||||
// Class initialization barrier for static methods
|
// Class initialization barrier for static methods
|
||||||
|
address c2i_no_clinit_check_entry = NULL;
|
||||||
if (VM_Version::supports_fast_class_init_checks()) {
|
if (VM_Version::supports_fast_class_init_checks()) {
|
||||||
Label L_skip_barrier;
|
Label L_skip_barrier;
|
||||||
Register method = rbx;
|
Register method = rbx;
|
||||||
@ -993,12 +991,16 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||||||
__ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
|
__ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
|
||||||
|
|
||||||
__ bind(L_skip_barrier);
|
__ bind(L_skip_barrier);
|
||||||
|
c2i_no_clinit_check_entry = __ pc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||||
|
bs->c2i_entry_barrier(masm);
|
||||||
|
|
||||||
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
|
||||||
|
|
||||||
__ flush();
|
__ flush();
|
||||||
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||||
|
@ -146,6 +146,12 @@ address Method::get_c2i_unverified_entry() {
|
|||||||
return adapter()->get_c2i_unverified_entry();
|
return adapter()->get_c2i_unverified_entry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address Method::get_c2i_no_clinit_check_entry() {
|
||||||
|
assert(VM_Version::supports_fast_class_init_checks(), "");
|
||||||
|
assert(adapter() != NULL, "must have");
|
||||||
|
return adapter()->get_c2i_no_clinit_check_entry();
|
||||||
|
}
|
||||||
|
|
||||||
char* Method::name_and_sig_as_C_string() const {
|
char* Method::name_and_sig_as_C_string() const {
|
||||||
return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature());
|
return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature());
|
||||||
}
|
}
|
||||||
@ -1048,7 +1054,7 @@ void Method::unlink_method() {
|
|||||||
_c2i_entry ---------------------------------+->[c2i entry..]
|
_c2i_entry ---------------------------------+->[c2i entry..]
|
||||||
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
|
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
|
||||||
_from_interpreted_entry | _c2i_unverified_entry | |
|
_from_interpreted_entry | _c2i_unverified_entry | |
|
||||||
| | | |
|
| | _c2i_no_clinit_check_entry| |
|
||||||
| | (_cds_entry_table: CODE) | |
|
| | (_cds_entry_table: CODE) | |
|
||||||
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
|
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
|
||||||
| | (allocated at run time) | |
|
| | (allocated at run time) | |
|
||||||
|
@ -481,6 +481,7 @@ class Method : public Metadata {
|
|||||||
address get_i2c_entry();
|
address get_i2c_entry();
|
||||||
address get_c2i_entry();
|
address get_c2i_entry();
|
||||||
address get_c2i_unverified_entry();
|
address get_c2i_unverified_entry();
|
||||||
|
address get_c2i_no_clinit_check_entry();
|
||||||
AdapterHandlerEntry* adapter() const {
|
AdapterHandlerEntry* adapter() const {
|
||||||
return constMethod()->adapter();
|
return constMethod()->adapter();
|
||||||
}
|
}
|
||||||
|
@ -1446,7 +1446,19 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread))
|
|||||||
guarantee(callee != NULL && callee->is_method(), "bad handshake");
|
guarantee(callee != NULL && callee->is_method(), "bad handshake");
|
||||||
thread->set_vm_result_2(callee);
|
thread->set_vm_result_2(callee);
|
||||||
thread->set_callee_target(NULL);
|
thread->set_callee_target(NULL);
|
||||||
return callee->get_c2i_entry();
|
if (caller_frame.is_entry_frame() && VM_Version::supports_fast_class_init_checks()) {
|
||||||
|
// Bypass class initialization checks in c2i when caller is in native.
|
||||||
|
// JNI calls to static methods don't have class initialization checks.
|
||||||
|
// Fast class initialization checks are present in c2i adapters and call into
|
||||||
|
// SharedRuntime::handle_wrong_method() on the slow path.
|
||||||
|
//
|
||||||
|
// JVM upcalls may land here as well, but there's a proper check present in
|
||||||
|
// LinkResolver::resolve_static_call (called from JavaCalls::call_static),
|
||||||
|
// so bypassing it in c2i adapter is benign.
|
||||||
|
return callee->get_c2i_no_clinit_check_entry();
|
||||||
|
} else {
|
||||||
|
return callee->get_c2i_entry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be compiled to compiled path which is safe to stackwalk
|
// Must be compiled to compiled path which is safe to stackwalk
|
||||||
@ -2450,9 +2462,9 @@ class AdapterHandlerTable : public BasicHashtable<mtCode> {
|
|||||||
: BasicHashtable<mtCode>(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { }
|
: BasicHashtable<mtCode>(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { }
|
||||||
|
|
||||||
// Create a new entry suitable for insertion in the table
|
// Create a new entry suitable for insertion in the table
|
||||||
AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
|
AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
|
||||||
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash());
|
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash());
|
||||||
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
((CDSAdapterHandlerEntry*)entry)->init();
|
((CDSAdapterHandlerEntry*)entry)->init();
|
||||||
}
|
}
|
||||||
@ -2601,8 +2613,9 @@ void AdapterHandlerLibrary::initialize() {
|
|||||||
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
|
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
|
||||||
address i2c_entry,
|
address i2c_entry,
|
||||||
address c2i_entry,
|
address c2i_entry,
|
||||||
address c2i_unverified_entry) {
|
address c2i_unverified_entry,
|
||||||
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
address c2i_no_clinit_check_entry) {
|
||||||
|
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
|
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
|
||||||
@ -2778,6 +2791,7 @@ address AdapterHandlerEntry::base_address() {
|
|||||||
if (base == NULL) base = _c2i_entry;
|
if (base == NULL) base = _c2i_entry;
|
||||||
assert(base <= _c2i_entry || _c2i_entry == NULL, "");
|
assert(base <= _c2i_entry || _c2i_entry == NULL, "");
|
||||||
assert(base <= _c2i_unverified_entry || _c2i_unverified_entry == NULL, "");
|
assert(base <= _c2i_unverified_entry || _c2i_unverified_entry == NULL, "");
|
||||||
|
assert(base <= _c2i_no_clinit_check_entry || _c2i_no_clinit_check_entry == NULL, "");
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2791,6 +2805,8 @@ void AdapterHandlerEntry::relocate(address new_base) {
|
|||||||
_c2i_entry += delta;
|
_c2i_entry += delta;
|
||||||
if (_c2i_unverified_entry != NULL)
|
if (_c2i_unverified_entry != NULL)
|
||||||
_c2i_unverified_entry += delta;
|
_c2i_unverified_entry += delta;
|
||||||
|
if (_c2i_no_clinit_check_entry != NULL)
|
||||||
|
_c2i_no_clinit_check_entry += delta;
|
||||||
assert(base_address() == new_base, "");
|
assert(base_address() == new_base, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3129,10 +3145,20 @@ void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
|
void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
|
||||||
st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
|
st->print("AHE@" INTPTR_FORMAT ": %s", p2i(this), fingerprint()->as_string());
|
||||||
p2i(this), fingerprint()->as_string(),
|
if (get_i2c_entry() != NULL) {
|
||||||
p2i(get_i2c_entry()), p2i(get_c2i_entry()), p2i(get_c2i_unverified_entry()));
|
st->print(" i2c: " INTPTR_FORMAT, p2i(get_i2c_entry()));
|
||||||
|
}
|
||||||
|
if (get_c2i_entry() != NULL) {
|
||||||
|
st->print(" c2i: " INTPTR_FORMAT, p2i(get_c2i_entry()));
|
||||||
|
}
|
||||||
|
if (get_c2i_unverified_entry() != NULL) {
|
||||||
|
st->print(" c2iUV: " INTPTR_FORMAT, p2i(get_c2i_unverified_entry()));
|
||||||
|
}
|
||||||
|
if (get_c2i_no_clinit_check_entry() != NULL) {
|
||||||
|
st->print(" c2iNCI: " INTPTR_FORMAT, p2i(get_c2i_no_clinit_check_entry()));
|
||||||
|
}
|
||||||
|
st->cr();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
|
@ -636,6 +636,7 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
|||||||
address _i2c_entry;
|
address _i2c_entry;
|
||||||
address _c2i_entry;
|
address _c2i_entry;
|
||||||
address _c2i_unverified_entry;
|
address _c2i_unverified_entry;
|
||||||
|
address _c2i_no_clinit_check_entry;
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Captures code and signature used to generate this adapter when
|
// Captures code and signature used to generate this adapter when
|
||||||
@ -644,11 +645,12 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
|||||||
int _saved_code_length;
|
int _saved_code_length;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
|
void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
|
||||||
_fingerprint = fingerprint;
|
_fingerprint = fingerprint;
|
||||||
_i2c_entry = i2c_entry;
|
_i2c_entry = i2c_entry;
|
||||||
_c2i_entry = c2i_entry;
|
_c2i_entry = c2i_entry;
|
||||||
_c2i_unverified_entry = c2i_unverified_entry;
|
_c2i_unverified_entry = c2i_unverified_entry;
|
||||||
|
_c2i_no_clinit_check_entry = c2i_no_clinit_check_entry;
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
_saved_code = NULL;
|
_saved_code = NULL;
|
||||||
_saved_code_length = 0;
|
_saved_code_length = 0;
|
||||||
@ -661,9 +663,11 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
|||||||
AdapterHandlerEntry();
|
AdapterHandlerEntry();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
address get_i2c_entry() const { return _i2c_entry; }
|
address get_i2c_entry() const { return _i2c_entry; }
|
||||||
address get_c2i_entry() const { return _c2i_entry; }
|
address get_c2i_entry() const { return _c2i_entry; }
|
||||||
address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
|
address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
|
||||||
|
address get_c2i_no_clinit_check_entry() const { return _c2i_no_clinit_check_entry; }
|
||||||
|
|
||||||
address base_address();
|
address base_address();
|
||||||
void relocate(address new_base);
|
void relocate(address new_base);
|
||||||
|
|
||||||
@ -709,7 +713,10 @@ class AdapterHandlerLibrary: public AllStatic {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
|
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
|
||||||
address i2c_entry, address c2i_entry, address c2i_unverified_entry);
|
address i2c_entry,
|
||||||
|
address c2i_entry,
|
||||||
|
address c2i_unverified_entry,
|
||||||
|
address c2i_no_clinit_check_entry = NULL);
|
||||||
static void create_native_wrapper(const methodHandle& method);
|
static void create_native_wrapper(const methodHandle& method);
|
||||||
static AdapterHandlerEntry* get_adapter(const methodHandle& method);
|
static AdapterHandlerEntry* get_adapter(const methodHandle& method);
|
||||||
|
|
||||||
|
@ -2969,11 +2969,6 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// callee_target is never live across a gc point so NULL it here should
|
|
||||||
// it still contain a methdOop.
|
|
||||||
|
|
||||||
set_callee_target(NULL);
|
|
||||||
|
|
||||||
assert(vframe_array_head() == NULL, "deopt in progress at a safepoint!");
|
assert(vframe_array_head() == NULL, "deopt in progress at a safepoint!");
|
||||||
// If we have deferred set_locals there might be oops waiting to be
|
// If we have deferred set_locals there might be oops waiting to be
|
||||||
// written
|
// written
|
||||||
|
@ -27,24 +27,24 @@
|
|||||||
*
|
*
|
||||||
* @requires !vm.graal.enabled
|
* @requires !vm.graal.enabled
|
||||||
*
|
*
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=false ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=false -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=true ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=true -Xcheck:jni ClassInitBarrier
|
||||||
*
|
*
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -Xcheck:jni ClassInitBarrier
|
||||||
*
|
*
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -Xcheck:jni ClassInitBarrier
|
||||||
*
|
*
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
*
|
*
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* ClassInitBarrier
|
* @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import jdk.test.lib.Asserts;
|
import jdk.test.lib.Asserts;
|
||||||
@ -70,6 +70,10 @@ public class ClassInitBarrier {
|
|||||||
static class Test {
|
static class Test {
|
||||||
static class A {
|
static class A {
|
||||||
static {
|
static {
|
||||||
|
if (!init(B.class)) {
|
||||||
|
throw new Error("init failed");
|
||||||
|
}
|
||||||
|
|
||||||
changePhase(Phase.IN_PROGRESS);
|
changePhase(Phase.IN_PROGRESS);
|
||||||
runTests(); // interpreted mode
|
runTests(); // interpreted mode
|
||||||
warmup(); // trigger compilation
|
warmup(); // trigger compilation
|
||||||
@ -89,13 +93,15 @@ public class ClassInitBarrier {
|
|||||||
|
|
||||||
int f;
|
int f;
|
||||||
void m() {}
|
void m() {}
|
||||||
|
|
||||||
|
static native boolean init(Class<B> cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class B extends A {}
|
static class B extends A {}
|
||||||
|
|
||||||
static void testInvokeStatic(Runnable action) { A.staticM(action); }
|
static void testInvokeStatic(Runnable action) { A.staticM(action); }
|
||||||
static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
|
static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
|
||||||
static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
|
static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
|
||||||
|
|
||||||
static int testGetStatic(Runnable action) { int v = A.staticF; action.run(); return v; }
|
static int testGetStatic(Runnable action) { int v = A.staticF; action.run(); return v; }
|
||||||
static void testPutStatic(Runnable action) { A.staticF = 1; action.run(); }
|
static void testPutStatic(Runnable action) { A.staticF = 1; action.run(); }
|
||||||
@ -106,20 +112,45 @@ public class ClassInitBarrier {
|
|||||||
static void testPutField(A recv, Runnable action) { recv.f = 1; action.run(); }
|
static void testPutField(A recv, Runnable action) { recv.f = 1; action.run(); }
|
||||||
static void testInvokeVirtual(A recv, Runnable action) { recv.m(); action.run(); }
|
static void testInvokeVirtual(A recv, Runnable action) { recv.m(); action.run(); }
|
||||||
|
|
||||||
|
static native void testInvokeStaticJNI(Runnable action);
|
||||||
|
static native void testInvokeStaticSyncJNI(Runnable action);
|
||||||
|
static native void testInvokeStaticNativeJNI(Runnable action);
|
||||||
|
|
||||||
|
static native int testGetStaticJNI(Runnable action);
|
||||||
|
static native void testPutStaticJNI(Runnable action);
|
||||||
|
static native A testNewInstanceAJNI(Runnable action);
|
||||||
|
static native B testNewInstanceBJNI(Runnable action);
|
||||||
|
|
||||||
|
static native int testGetFieldJNI(A recv, Runnable action);
|
||||||
|
static native void testPutFieldJNI(A recv, Runnable action);
|
||||||
|
static native void testInvokeVirtualJNI(A recv, Runnable action);
|
||||||
|
|
||||||
static void runTests() {
|
static void runTests() {
|
||||||
checkBlockingAction(Test::testInvokeStatic); // invokestatic
|
checkBlockingAction(Test::testInvokeStatic); // invokestatic
|
||||||
checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
|
|
||||||
checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
|
checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
|
||||||
|
checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
|
||||||
checkBlockingAction(Test::testGetStatic); // getstatic
|
checkBlockingAction(Test::testGetStatic); // getstatic
|
||||||
checkBlockingAction(Test::testPutStatic); // putstatic
|
checkBlockingAction(Test::testPutStatic); // putstatic
|
||||||
checkBlockingAction(Test::testNewInstanceA); // new
|
checkBlockingAction(Test::testNewInstanceA); // new
|
||||||
|
|
||||||
|
checkNonBlockingAction(Test::testInvokeStaticJNI); // invokestatic
|
||||||
|
checkNonBlockingAction(Test::testInvokeStaticSyncJNI); // invokestatic
|
||||||
|
checkNonBlockingAction(Test::testInvokeStaticNativeJNI); // invokestatic
|
||||||
|
checkNonBlockingAction(Test::testGetStaticJNI); // getstatic
|
||||||
|
checkNonBlockingAction(Test::testPutStaticJNI); // putstatic
|
||||||
|
checkBlockingAction(Test::testNewInstanceAJNI); // new
|
||||||
|
|
||||||
A recv = testNewInstanceB(NON_BLOCKING.get()); // trigger B initialization
|
A recv = testNewInstanceB(NON_BLOCKING.get()); // trigger B initialization
|
||||||
checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
|
checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
|
||||||
|
|
||||||
checkNonBlockingAction(recv, Test::testGetField); // getfield
|
checkNonBlockingAction(recv, Test::testGetField); // getfield
|
||||||
checkNonBlockingAction(recv, Test::testPutField); // putfield
|
checkNonBlockingAction(recv, Test::testPutField); // putfield
|
||||||
checkNonBlockingAction(recv, Test::testInvokeVirtual); // invokevirtual
|
checkNonBlockingAction(recv, Test::testInvokeVirtual); // invokevirtual
|
||||||
|
|
||||||
|
checkNonBlockingAction(Test::testNewInstanceBJNI); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
|
||||||
|
checkNonBlockingAction(recv, Test::testGetFieldJNI); // getfield
|
||||||
|
checkNonBlockingAction(recv, Test::testPutFieldJNI); // putfield
|
||||||
|
checkNonBlockingAction(recv, Test::testInvokeVirtualJNI); // invokevirtual
|
||||||
}
|
}
|
||||||
|
|
||||||
static void warmup() {
|
static void warmup() {
|
||||||
|
@ -25,6 +25,17 @@
|
|||||||
|
|
||||||
static jmethodID methodId;
|
static jmethodID methodId;
|
||||||
|
|
||||||
|
static jclass test_class_A;
|
||||||
|
static jclass test_class_B;
|
||||||
|
|
||||||
|
static jmethodID test_staticM_id;
|
||||||
|
static jmethodID test_staticS_id;
|
||||||
|
static jmethodID test_staticN_id;
|
||||||
|
static jmethodID test_A_m_id;
|
||||||
|
|
||||||
|
static jfieldID test_staticF_id;
|
||||||
|
static jfieldID test_A_f_id;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_init(JNIEnv* env, jclass cls) {
|
JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_init(JNIEnv* env, jclass cls) {
|
||||||
jclass runnable = env->FindClass("java/lang/Runnable");
|
jclass runnable = env->FindClass("java/lang/Runnable");
|
||||||
@ -36,7 +47,103 @@ extern "C" {
|
|||||||
return JNI_TRUE;
|
return JNI_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_00024Test_00024A_init(JNIEnv* env, jclass cls, jclass arg1) {
|
||||||
|
test_class_A = (jclass)env->NewGlobalRef(cls);
|
||||||
|
if (test_class_A == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_class_B = (jclass)env->NewGlobalRef(arg1);
|
||||||
|
if (test_class_B == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_staticM_id = env->GetStaticMethodID(test_class_A, "staticM", "(Ljava/lang/Runnable;)V");
|
||||||
|
if (test_staticM_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_staticS_id = env->GetStaticMethodID(test_class_A, "staticS", "(Ljava/lang/Runnable;)V");
|
||||||
|
if (test_staticS_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_staticN_id = env->GetStaticMethodID(test_class_A, "staticN", "(Ljava/lang/Runnable;)V");
|
||||||
|
if (test_staticN_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_A_m_id = env->GetMethodID(test_class_A, "m", "()V");
|
||||||
|
if (test_A_m_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_staticF_id = env->GetStaticFieldID(test_class_A, "staticF", "I");
|
||||||
|
if (test_staticF_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
test_A_f_id = env->GetFieldID(test_class_A, "f", "I");
|
||||||
|
if (test_A_f_id == NULL) return JNI_FALSE;
|
||||||
|
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_00024A_staticN(JNIEnv* env, jclass cls, jobject action) {
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_00024A_staticN(JNIEnv* env, jclass cls, jobject action) {
|
||||||
env->CallVoidMethod(action, methodId);
|
env->CallVoidMethod(action, methodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
env->CallStaticVoidMethod(test_class_A, test_staticM_id, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticSyncJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
env->CallStaticVoidMethod(test_class_A, test_staticS_id, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticNativeJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
env->CallStaticVoidMethod(test_class_A, test_staticN_id, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_ClassInitBarrier_00024Test_testGetStaticJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
jint v = env->GetStaticIntField(test_class_A, test_staticF_id); // int v = A.staticF;
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testPutStaticJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
env->SetStaticIntField(test_class_A, test_staticF_id, 1); // A.staticF = 1;
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_ClassInitBarrier_00024Test_testNewInstanceAJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
jobject obj = env->AllocObject(test_class_A); // A obj = new A();
|
||||||
|
if (env->ExceptionOccurred()) {
|
||||||
|
return NULL;
|
||||||
|
} else if (obj == NULL) {
|
||||||
|
jclass errorClass = env->FindClass("java/lang/AssertionError");
|
||||||
|
int ret = env->ThrowNew(errorClass, "JNI: AllocObject: allocation failed, but no exception thrown");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_ClassInitBarrier_00024Test_testNewInstanceBJNI(JNIEnv* env, jclass cls, jobject action) {
|
||||||
|
jobject obj = env->AllocObject(test_class_B); // B obj = new B();
|
||||||
|
if (env->ExceptionOccurred()) {
|
||||||
|
return NULL;
|
||||||
|
} else if (obj == NULL) {
|
||||||
|
jclass errorClass = env->FindClass("java/lang/AssertionError");
|
||||||
|
int ret = env->ThrowNew(errorClass, "JNI: AllocObject: allocation failed, but no exception thrown");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_ClassInitBarrier_00024Test_testGetFieldJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
|
||||||
|
jint v = env->GetIntField(recv, test_A_f_id); // int v = recv.f;
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testPutFieldJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
|
||||||
|
env->SetIntField(recv, test_A_f_id, 1); // A.staticF = 1;
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeVirtualJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
|
||||||
|
env->CallVoidMethod(recv, test_A_m_id); // recv.m();
|
||||||
|
if (env->ExceptionOccurred()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
env->CallVoidMethod(action, methodId); // action.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user