8227260: JNI upcalls should bypass class initialization barrier in c2i adapter

Reviewed-by: eosterlund, dholmes, mdoerr
This commit is contained in:
Vladimir Ivanov 2019-07-24 10:50:40 +03:00
parent 78c7364c17
commit 32eb2e45b6
10 changed files with 223 additions and 44 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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) | |

View File

@ -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();
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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() {

View File

@ -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();
}
}