ffi 1.15: #jni_call(void) codegen — make-green

New `.jni_msg_send` IR opcode carrying `{env, target, name, sig,
args[], is_static}`. `lowerFfiIntrinsicCall` now dispatches on
`fic.kind`: `.objc_call` keeps the existing path; `.jni_call` and
`.jni_static_call` route through `lowerJniCall`, which emits the new
opcode.

emit_llvm.zig expands `.jni_msg_send` into the JNI vtable
indirection:

  %ifs              = load ptr, %env                  ; vtable
  %get_obj_class    = load ptr, gep(%ifs, i32 31)
  %cls              = call ptr %get_obj_class(%env, %target)
  %get_method_id    = load ptr, gep(%ifs, i32 33)
  %mid              = call ptr %get_method_id(%env, %cls, %name, %sig)
  %call_void_method = load ptr, gep(%ifs, i32 61)
  call void %call_void_method(%env, %target, %mid, args...)

Per step 1.15's scope: only `.jni_call` (instance) + `void` return
are wired through the switch. `.jni_static_call` (1.23) and the
non-void returns (1.18–1.22) drop to a placeholder `LLVMGetUndef` so
the build doesn't fault — the next-step commits flip those arms one
shape at a time. Method-ID caching is step 1.17.

Two small helpers landed alongside:
- `loadJniFn(ifs, offset, name)` — GEP into the vtable + load.
- `extractSlicePtr(val)` — string literals lower as `{ptr, i64}`
  slices in sx IR; JNI's `GetMethodID` expects raw C strings, so
  this extracts field 0 when the source is a slice.

Android cross-compile now passes for `examples/ffi-jni-call-02-void.sx`
(2/2 cross targets green). Host run_examples still passes 112/112.
Chess iOS-sim + Android both compile clean.
This commit is contained in:
agra
2026-05-19 21:32:18 +03:00
parent 134c197dd4
commit 9afcaa5af0
5 changed files with 159 additions and 5 deletions

View File

@@ -321,6 +321,14 @@ fn printInst(instruction: *const Inst, ref_idx: u32, tt: *const TypeTable, write
try writeArgs(c.args, writer);
try writer.writeAll(") : ");
},
.jni_msg_send => |c| {
const kind: []const u8 = if (c.is_static) "static" else "instance";
try writer.print("jni_msg_send {s} env=%{d} target=%{d} name=%{d} sig=%{d}(", .{
kind, c.env.index(), c.target.index(), c.name.index(), c.sig.index(),
});
try writeArgs(c.args, writer);
try writer.writeAll(") : ");
},
.compiler_call => |cc| {
const name = tt.getString(@enumFromInt(cc.name));
try writer.print("compiler_call \"{s}\"(", .{name});