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();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = NULL;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -1295,11 +1296,12 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
__ bctr();
|
||||
|
||||
__ 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);
|
||||
|
||||
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
|
||||
|
@ -2713,6 +2713,7 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
address c2i_entry = __ pc();
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = NULL;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
|
||||
@ -2729,11 +2730,12 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
__ z_br(klass);
|
||||
|
||||
__ 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);
|
||||
|
||||
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
|
||||
|
@ -971,10 +971,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
|
||||
address c2i_entry = __ pc();
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->c2i_entry_barrier(masm);
|
||||
|
||||
// Class initialization barrier for static methods
|
||||
address c2i_no_clinit_check_entry = NULL;
|
||||
if (VM_Version::supports_fast_class_init_checks()) {
|
||||
Label L_skip_barrier;
|
||||
Register method = rbx;
|
||||
@ -993,12 +991,16 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
||||
__ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
|
||||
|
||||
__ 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);
|
||||
|
||||
__ 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,
|
||||
|
@ -146,6 +146,12 @@ address Method::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 {
|
||||
return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature());
|
||||
}
|
||||
@ -1048,7 +1054,7 @@ void Method::unlink_method() {
|
||||
_c2i_entry ---------------------------------+->[c2i entry..]
|
||||
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
|
||||
_from_interpreted_entry | _c2i_unverified_entry | |
|
||||
| | | |
|
||||
| | _c2i_no_clinit_check_entry| |
|
||||
| | (_cds_entry_table: CODE) | |
|
||||
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
|
||||
| | (allocated at run time) | |
|
||||
|
@ -481,6 +481,7 @@ class Method : public Metadata {
|
||||
address get_i2c_entry();
|
||||
address get_c2i_entry();
|
||||
address get_c2i_unverified_entry();
|
||||
address get_c2i_no_clinit_check_entry();
|
||||
AdapterHandlerEntry* adapter() const {
|
||||
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");
|
||||
thread->set_vm_result_2(callee);
|
||||
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
|
||||
@ -2450,9 +2462,9 @@ class AdapterHandlerTable : public BasicHashtable<mtCode> {
|
||||
: BasicHashtable<mtCode>(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { }
|
||||
|
||||
// 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());
|
||||
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) {
|
||||
((CDSAdapterHandlerEntry*)entry)->init();
|
||||
}
|
||||
@ -2601,8 +2613,9 @@ void AdapterHandlerLibrary::initialize() {
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
|
||||
address i2c_entry,
|
||||
address c2i_entry,
|
||||
address c2i_unverified_entry) {
|
||||
return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
|
||||
address 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) {
|
||||
@ -2778,6 +2791,7 @@ address AdapterHandlerEntry::base_address() {
|
||||
if (base == NULL) base = _c2i_entry;
|
||||
assert(base <= _c2i_entry || _c2i_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;
|
||||
}
|
||||
|
||||
@ -2791,6 +2805,8 @@ void AdapterHandlerEntry::relocate(address new_base) {
|
||||
_c2i_entry += delta;
|
||||
if (_c2i_unverified_entry != NULL)
|
||||
_c2i_unverified_entry += delta;
|
||||
if (_c2i_no_clinit_check_entry != NULL)
|
||||
_c2i_no_clinit_check_entry += delta;
|
||||
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 {
|
||||
st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
|
||||
p2i(this), fingerprint()->as_string(),
|
||||
p2i(get_i2c_entry()), p2i(get_c2i_entry()), p2i(get_c2i_unverified_entry()));
|
||||
|
||||
st->print("AHE@" INTPTR_FORMAT ": %s", p2i(this), fingerprint()->as_string());
|
||||
if (get_i2c_entry() != NULL) {
|
||||
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
|
||||
|
@ -636,6 +636,7 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
address _i2c_entry;
|
||||
address _c2i_entry;
|
||||
address _c2i_unverified_entry;
|
||||
address _c2i_no_clinit_check_entry;
|
||||
|
||||
#ifdef ASSERT
|
||||
// Captures code and signature used to generate this adapter when
|
||||
@ -644,11 +645,12 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
int _saved_code_length;
|
||||
#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;
|
||||
_i2c_entry = i2c_entry;
|
||||
_c2i_entry = c2i_entry;
|
||||
_c2i_unverified_entry = c2i_unverified_entry;
|
||||
_c2i_no_clinit_check_entry = c2i_no_clinit_check_entry;
|
||||
#ifdef ASSERT
|
||||
_saved_code = NULL;
|
||||
_saved_code_length = 0;
|
||||
@ -661,9 +663,11 @@ class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> {
|
||||
AdapterHandlerEntry();
|
||||
|
||||
public:
|
||||
address get_i2c_entry() const { return _i2c_entry; }
|
||||
address get_c2i_entry() const { return _c2i_entry; }
|
||||
address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
|
||||
address get_i2c_entry() const { return _i2c_entry; }
|
||||
address get_c2i_entry() const { return _c2i_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();
|
||||
void relocate(address new_base);
|
||||
|
||||
@ -709,7 +713,10 @@ class AdapterHandlerLibrary: public AllStatic {
|
||||
public:
|
||||
|
||||
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 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!");
|
||||
// If we have deferred set_locals there might be oops waiting to be
|
||||
// written
|
||||
|
@ -27,24 +27,24 @@
|
||||
*
|
||||
* @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=true 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 -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=true 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 -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=true 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 -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=true -XX:CompileCommand=dontinline,*::static* 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=true -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* -Xcheck:jni 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* -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=true -XX:CompileCommand=exclude,*::static* 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=true -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* -Xcheck:jni 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* -Xcheck:jni ClassInitBarrier
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
@ -70,6 +70,10 @@ public class ClassInitBarrier {
|
||||
static class Test {
|
||||
static class A {
|
||||
static {
|
||||
if (!init(B.class)) {
|
||||
throw new Error("init failed");
|
||||
}
|
||||
|
||||
changePhase(Phase.IN_PROGRESS);
|
||||
runTests(); // interpreted mode
|
||||
warmup(); // trigger compilation
|
||||
@ -89,13 +93,15 @@ public class ClassInitBarrier {
|
||||
|
||||
int f;
|
||||
void m() {}
|
||||
|
||||
static native boolean init(Class<B> cls);
|
||||
}
|
||||
|
||||
static class B extends A {}
|
||||
|
||||
static void testInvokeStatic(Runnable action) { A.staticM(action); }
|
||||
static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
|
||||
static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
|
||||
static void testInvokeStatic(Runnable action) { A.staticM(action); }
|
||||
static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
|
||||
static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
|
||||
|
||||
static int testGetStatic(Runnable action) { int v = A.staticF; action.run(); return v; }
|
||||
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 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() {
|
||||
checkBlockingAction(Test::testInvokeStatic); // invokestatic
|
||||
checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
|
||||
checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
|
||||
checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
|
||||
checkBlockingAction(Test::testGetStatic); // getstatic
|
||||
checkBlockingAction(Test::testPutStatic); // putstatic
|
||||
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
|
||||
checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
|
||||
|
||||
checkNonBlockingAction(recv, Test::testGetField); // getfield
|
||||
checkNonBlockingAction(recv, Test::testPutField); // putfield
|
||||
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() {
|
||||
|
@ -25,6 +25,17 @@
|
||||
|
||||
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" {
|
||||
JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_init(JNIEnv* env, jclass cls) {
|
||||
jclass runnable = env->FindClass("java/lang/Runnable");
|
||||
@ -36,7 +47,103 @@ extern "C" {
|
||||
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) {
|
||||
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…
Reference in New Issue
Block a user