ffi: lift JNI vtable offsets into a named-constants struct
The numeric slot indices (21, 31, 33, 49, 61) in the `#jni_call`
lowering are JNI-spec constants from `<jni.h>` but appeared as bare
magic numbers — only the trailing comment told you which JNI
function you were loading. Moving them into a private `const Jni`
namespace at file scope makes the call sites self-documenting:
loadJniFn(ifs, Jni.GetObjectClass, "jni.GetObjectClass")
loadJniFn(ifs, Jni.NewGlobalRef, "jni.NewGlobalRef")
loadJniFn(ifs, Jni.GetMethodID, "jni.GetMethodID")
switch (ret_ty_id) {
.void => Jni.CallVoidMethod,
.s32 => Jni.CallIntMethod,
...
}
Also pre-loaded the remaining Call<Type>Method slots (Object,
Boolean, Long, Float, Double) so steps 1.19–1.22 just add the
corresponding switch arm — no new magic-number lookups in the diff.
Behavior-preserving refactor: IR snapshots unchanged, all 113 host
tests still pass, both cross-compile tuples still green.
This commit is contained in:
@@ -29,6 +29,27 @@ fn isIdentByte(b: u8) bool {
|
||||
return (b >= 'a' and b <= 'z') or (b >= 'A' and b <= 'Z') or (b >= '0' and b <= '9') or b == '_';
|
||||
}
|
||||
|
||||
/// JNI vtable slot offsets — indices into the `JNINativeInterface`
|
||||
/// function-pointer array reachable via `*env`. Stable per the JNI
|
||||
/// spec across versions; locked to the documented order in
|
||||
/// `<jni.h>`. Slot numbers here MUST match the order of fields in
|
||||
/// the C `JNINativeInterface_` struct.
|
||||
const Jni = struct {
|
||||
const NewGlobalRef: u32 = 21;
|
||||
const GetObjectClass: u32 = 31;
|
||||
const GetMethodID: u32 = 33;
|
||||
// Call<Type>Method (instance, varargs variant). Each numeric type
|
||||
// has its own slot — distinct ABI per return type, so the JNI
|
||||
// runtime dispatches the right arg-shuffle for each.
|
||||
const CallObjectMethod: u32 = 34;
|
||||
const CallBooleanMethod: u32 = 37;
|
||||
const CallIntMethod: u32 = 49;
|
||||
const CallLongMethod: u32 = 52;
|
||||
const CallFloatMethod: u32 = 55;
|
||||
const CallDoubleMethod: u32 = 58;
|
||||
const CallVoidMethod: u32 = 61;
|
||||
};
|
||||
|
||||
// ── LLVMEmitter ─────────────────────────────────────────────────────────
|
||||
// Emits LLVM IR from an IR Module. This is the Phase 3 replacement for
|
||||
// the AST-based codegen.
|
||||
@@ -1219,8 +1240,8 @@ pub const LLVMEmitter = struct {
|
||||
}
|
||||
const ret_ty_id = instruction.ty;
|
||||
const call_method_offset: u32 = switch (ret_ty_id) {
|
||||
.void => 61, // CallVoidMethod
|
||||
.s32 => 49, // CallIntMethod
|
||||
.void => Jni.CallVoidMethod,
|
||||
.s32 => Jni.CallIntMethod,
|
||||
else => {
|
||||
self.mapRef(c.LLVMGetUndef(self.toLLVMType(instruction.ty)));
|
||||
return;
|
||||
@@ -1258,18 +1279,18 @@ pub const LLVMEmitter = struct {
|
||||
|
||||
// Miss path: GetObjectClass → NewGlobalRef → GetMethodID, then store both.
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, miss_bb);
|
||||
const get_obj_cls = self.loadJniFn(ifs, 31, "jni.GetObjectClass");
|
||||
const get_obj_cls = self.loadJniFn(ifs, Jni.GetObjectClass, "jni.GetObjectClass");
|
||||
var gocls_params = [_]c.LLVMTypeRef{ self.cached_ptr, self.cached_ptr };
|
||||
const gocls_ty = c.LLVMFunctionType(self.cached_ptr, &gocls_params, 2, 0);
|
||||
var gocls_args = [_]c.LLVMValueRef{ env, target };
|
||||
const local_cls = c.LLVMBuildCall2(self.builder, gocls_ty, get_obj_cls, &gocls_args, 2, "jni.cls");
|
||||
const new_global_ref = self.loadJniFn(ifs, 21, "jni.NewGlobalRef");
|
||||
const new_global_ref = self.loadJniFn(ifs, Jni.NewGlobalRef, "jni.NewGlobalRef");
|
||||
var ngref_params = [_]c.LLVMTypeRef{ self.cached_ptr, self.cached_ptr };
|
||||
const ngref_ty = c.LLVMFunctionType(self.cached_ptr, &ngref_params, 2, 0);
|
||||
var ngref_args = [_]c.LLVMValueRef{ env, local_cls };
|
||||
const global_cls = c.LLVMBuildCall2(self.builder, ngref_ty, new_global_ref, &ngref_args, 2, "jni.global.cls");
|
||||
_ = c.LLVMBuildStore(self.builder, global_cls, pair.cls_slot);
|
||||
const get_mid = self.loadJniFn(ifs, 33, "jni.GetMethodID");
|
||||
const get_mid = self.loadJniFn(ifs, Jni.GetMethodID, "jni.GetMethodID");
|
||||
var gmid_params = [_]c.LLVMTypeRef{ self.cached_ptr, self.cached_ptr, self.cached_ptr, self.cached_ptr };
|
||||
const gmid_ty = c.LLVMFunctionType(self.cached_ptr, &gmid_params, 4, 0);
|
||||
var gmid_args = [_]c.LLVMValueRef{ env, global_cls, name_ptr, sig_ptr };
|
||||
@@ -1286,12 +1307,12 @@ pub const LLVMEmitter = struct {
|
||||
c.LLVMAddIncoming(phi, &phi_vals, &phi_blocks, 2);
|
||||
break :blk phi;
|
||||
} else blk: {
|
||||
const get_obj_cls = self.loadJniFn(ifs, 31, "jni.GetObjectClass");
|
||||
const get_obj_cls = self.loadJniFn(ifs, Jni.GetObjectClass, "jni.GetObjectClass");
|
||||
var gocls_params = [_]c.LLVMTypeRef{ self.cached_ptr, self.cached_ptr };
|
||||
const gocls_ty = c.LLVMFunctionType(self.cached_ptr, &gocls_params, 2, 0);
|
||||
var gocls_args = [_]c.LLVMValueRef{ env, target };
|
||||
const cls = c.LLVMBuildCall2(self.builder, gocls_ty, get_obj_cls, &gocls_args, 2, "jni.cls");
|
||||
const get_mid = self.loadJniFn(ifs, 33, "jni.GetMethodID");
|
||||
const get_mid = self.loadJniFn(ifs, Jni.GetMethodID, "jni.GetMethodID");
|
||||
var gmid_params = [_]c.LLVMTypeRef{ self.cached_ptr, self.cached_ptr, self.cached_ptr, self.cached_ptr };
|
||||
const gmid_ty = c.LLVMFunctionType(self.cached_ptr, &gmid_params, 4, 0);
|
||||
var gmid_args = [_]c.LLVMValueRef{ env, cls, name_ptr, sig_ptr };
|
||||
|
||||
Reference in New Issue
Block a user