# HG changeset patch # User vlivanov # Date 1563954640 -10800 # Node ID 6a159c6c23ccd0029140ab91653442e412305ce5 # Parent 7e8f6c56c285ef089a1a71ffdeb786e511d3357a 8227260: JNI upcalls should bypass class initialization barrier in c2i adapter Reviewed-by: eosterlund, dholmes, mdoerr diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -1277,6 +1277,7 @@ 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 @@ __ 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 diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/cpu/s390/sharedRuntime_s390.cpp --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -2713,6 +2713,7 @@ 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 @@ __ 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 diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -971,10 +971,8 @@ 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 @@ __ 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, diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/share/oops/method.cpp --- a/src/hotspot/share/oops/method.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/share/oops/method.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -146,6 +146,12 @@ 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 @@ _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) | | diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/share/oops/method.hpp --- a/src/hotspot/share/oops/method.hpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/share/oops/method.hpp Wed Jul 24 10:50:40 2019 +0300 @@ -481,6 +481,7 @@ 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(); } diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/share/runtime/sharedRuntime.cpp --- a/src/hotspot/share/runtime/sharedRuntime.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/share/runtime/sharedRuntime.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -1446,7 +1446,19 @@ 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 @@ : BasicHashtable(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::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 @@ 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 @@ 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 @@ _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 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 diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/share/runtime/sharedRuntime.hpp --- a/src/hotspot/share/runtime/sharedRuntime.hpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/share/runtime/sharedRuntime.hpp Wed Jul 24 10:50:40 2019 +0300 @@ -636,6 +636,7 @@ 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 @@ 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 @@ 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 @@ 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); diff -r 7e8f6c56c285 -r 6a159c6c23cc src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/src/hotspot/share/runtime/thread.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -2969,11 +2969,6 @@ } } - // 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 diff -r 7e8f6c56c285 -r 6a159c6c23cc test/hotspot/jtreg/runtime/clinit/ClassInitBarrier.java --- a/test/hotspot/jtreg/runtime/clinit/ClassInitBarrier.java Wed Jul 24 10:09:30 2019 +0800 +++ b/test/hotspot/jtreg/runtime/clinit/ClassInitBarrier.java Wed Jul 24 10:50:40 2019 +0300 @@ -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 @@ 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 @@ int f; void m() {} + + static native boolean init(Class 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 @@ 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::testInvokeStaticSync); // invokestatic checkBlockingAction(Test::testInvokeStaticNative); // invokestatic - checkBlockingAction(Test::testInvokeStaticSync); // 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() { diff -r 7e8f6c56c285 -r 6a159c6c23cc test/hotspot/jtreg/runtime/clinit/libClassInitBarrier.cpp --- a/test/hotspot/jtreg/runtime/clinit/libClassInitBarrier.cpp Wed Jul 24 10:09:30 2019 +0800 +++ b/test/hotspot/jtreg/runtime/clinit/libClassInitBarrier.cpp Wed Jul 24 10:50:40 2019 +0300 @@ -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 @@ 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(); + } }