Adds `examples/ffi-jni-call-03-methodid-sharing.sx` with two `#jni_call` sites against the same (class, method, sig). Today each site emits its own `GetObjectClass` + `GetMethodID` + `Call<Type>Method` sequence (8 vtable indirections total for the two-call test); 1.17 will collapse the two `GetMethodID` calls into a single cached `jmethodID` static slot populated at module init, mirroring the `OBJC_SELECTOR_REFERENCES_*` shape that 1.5 introduced for `#objc_call`. Runtime is a no-op — `unused_jni` is reachable through a runtime-readable `g_should_call` global that stays false, so the JNI dereferences never execute. A plain `if false` would get constant-folded, taking the function definition out of the IR entirely; the global keeps both the function and its body present for the IR-snapshot harness. IR snapshot at `tests/expected/ffi-jni-call-03-methodid-sharing.ir` locks the pre-caching shape. The next commit (1.17) updates it to the collapsed shape. 113/113 host tests pass.
31 lines
1.0 KiB
Plaintext
31 lines
1.0 KiB
Plaintext
// Phase 1 step 1.16 (PLAN-FFI.md): two `#jni_call` sites against the
|
|
// same (class, method, sig) tuple. Today each site emits its own
|
|
// `GetObjectClass` + `GetMethodID` call (no caching yet); after 1.17
|
|
// the lowering collapses to one cached `jmethodID` per unique
|
|
// (class, method, sig).
|
|
//
|
|
// Runtime: unreachable. The JNI dispatch is all indirect through
|
|
// `*env` — no external symbol declarations — so the IR loads cleanly
|
|
// into the host JIT, and the dereferences never execute because the
|
|
// guarding `g_should_call` global stays false. A plain `if false`
|
|
// would get constant-folded, taking the `unused_jni` body out of the
|
|
// IR with it; the runtime-readable global keeps the call alive so
|
|
// the JNI lowering is visible to the IR snapshot.
|
|
|
|
#import "modules/std.sx";
|
|
|
|
g_should_call : bool = false;
|
|
|
|
unused_jni :: (env: *void, target: *void) {
|
|
#jni_call(void)(env, target, "noop", "()V");
|
|
#jni_call(void)(env, target, "noop", "()V");
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
if g_should_call {
|
|
unused_jni(null, null);
|
|
}
|
|
print("ok\n");
|
|
0;
|
|
}
|