diff --git a/src/ir/emit_llvm.zig b/src/ir/emit_llvm.zig index 71bf732..2354b63 100644 --- a/src/ir/emit_llvm.zig +++ b/src/ir/emit_llvm.zig @@ -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 +/// ``. 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; + // CallMethod (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 };