// Phase 1 step 1.15 (PLAN-FFI.md): `#jni_call(void)` codegen. // // `#jni_call(T)(env, target, "method_name", "(Sig)RetSig", args...)` // dispatches a JNI instance-method call. The lowering hand-emits the // vtable indirection: // // ifs = *env // JNINativeInterface* // cls = ifs->GetObjectClass(env, target) // mid = ifs->GetMethodID(env, cls, name, sig) // ifs->CallMethod(env, target, mid, args...) // // Phase 1.17 introduces method-ID caching via static slots populated // at module-init; this step keeps the per-call-site lookup. // // Host can't dlopen libjvm via the JIT, so the JNI body is gated // behind `inline if OS == .android`. The macOS test path strips the // body and prints "skipped"; the cross_compile.sh Android target // verifies that the gated body actually compiles + links against // libjvm in the Android sysroot. #import "modules/std.sx"; #import "modules/compiler.sx"; main :: () -> s32 { inline if OS == .android { // Real Android entry passes env + target via android_main / // ANativeActivity (modules/platform/android.sx). For the cross- // compile-only test we just need the lowering to emit valid // IR; runtime correctness is exercised by the chess // sx_android_query_safe_insets path once Phase 1D for // sx_android_jni.c lands. env : *void = null; target : *void = null; #jni_call(void)(env, target, "noop", "()V"); } inline if OS != .android { print("skipped (not android)\n"); } 0; } // Android target requires `android_main` as the NDK entry — kept as // a 3-line trampoline so this example can pass through // `--target android` builds in `tests/cross_compile.sh`. android_main :: (app: *void) { inline if OS == .android { main(); } }