refactor(backend): extract JNI slot cache into ffi_ctors.zig (A7.3 slice 2a)
Move getOrCreateJniSlots (the cls/methodid slot-cache builder) out of emit_llvm.zig into the FfiCtors backend *LLVMEmitter facade. Behavior-preserving — self.* -> self.e.* only. - FfiCtors gains getOrCreateJniSlots (pub). The jni_slots cache + mangleJniKey stay on LLVMEmitter; mangleJniKey is widened to pub (the facade calls it back, like lazyDeclareCRuntime/emitPrivateCString), and JniSlotPair is widened to pub (the facade returns it; the call site consumes it). 1 call site routed via ffiCtors(). - emitJniConstructor intentionally NOT moved in this slice: it is emission-heavy (resolveRef/mapRef/coerceArg/getRefIRType/extractSlicePtr/loadJniFn/ emitCStringGlobal — 100+ internal callers for the first two), so relocating it would pub-expose the emitter's core value-emission machinery. Consistent with A7.2 keeping emitFieldValueGet in emit_llvm.zig. Pending an explicit decision. Gate: zig build, zig build test, bash tests/run_examples.sh -> 361/0 (JNI anchors 1402/1408/1418/1425 green, no churn).
This commit is contained in:
@@ -221,7 +221,7 @@ pub const LLVMEmitter = struct {
|
||||
param_index: u32,
|
||||
};
|
||||
|
||||
const JniSlotPair = struct {
|
||||
pub const JniSlotPair = struct {
|
||||
cls_slot: c.LLVMValueRef, // @SX_JNI_CLS_<key>: ptr (GlobalRef to jclass)
|
||||
mid_slot: c.LLVMValueRef, // @SX_JNI_MID_<key>: ptr (jmethodID)
|
||||
};
|
||||
@@ -623,43 +623,12 @@ pub const LLVMEmitter = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `{cls_slot, mid_slot}` global pair for the
|
||||
/// `(name, sig)` literal — created on first lookup, shared across
|
||||
/// later `#jni_call` sites with the same literal pair. Both
|
||||
/// slots are zero-initialized `ptr`; the call-site lowering does
|
||||
/// lazy population on first dispatch.
|
||||
fn getOrCreateJniSlots(self: *LLVMEmitter, name: []const u8, sig: []const u8) JniSlotPair {
|
||||
// Compose the key from name + a separator + sig. The separator
|
||||
// is a byte that can't appear in a JNI method name or signature
|
||||
// (NUL), so the same key never collides across distinct pairs.
|
||||
const key = std.fmt.allocPrint(self.alloc, "{s}\x00{s}", .{ name, sig }) catch unreachable;
|
||||
if (self.jni_slots.get(key)) |existing| {
|
||||
self.alloc.free(key);
|
||||
return existing;
|
||||
}
|
||||
const mangled = self.mangleJniKey(name, sig);
|
||||
defer self.alloc.free(mangled);
|
||||
const cls_name = std.fmt.allocPrintSentinel(self.alloc, "SX_JNI_CLS_{s}", .{mangled}, 0) catch unreachable;
|
||||
defer self.alloc.free(cls_name);
|
||||
const mid_name = std.fmt.allocPrintSentinel(self.alloc, "SX_JNI_MID_{s}", .{mangled}, 0) catch unreachable;
|
||||
defer self.alloc.free(mid_name);
|
||||
const cls_slot = c.LLVMAddGlobal(self.llvm_module, self.cached_ptr, cls_name.ptr);
|
||||
c.LLVMSetLinkage(cls_slot, c.LLVMInternalLinkage);
|
||||
c.LLVMSetInitializer(cls_slot, c.LLVMConstNull(self.cached_ptr));
|
||||
const mid_slot = c.LLVMAddGlobal(self.llvm_module, self.cached_ptr, mid_name.ptr);
|
||||
c.LLVMSetLinkage(mid_slot, c.LLVMInternalLinkage);
|
||||
c.LLVMSetInitializer(mid_slot, c.LLVMConstNull(self.cached_ptr));
|
||||
const pair = JniSlotPair{ .cls_slot = cls_slot, .mid_slot = mid_slot };
|
||||
self.jni_slots.put(key, pair) catch unreachable;
|
||||
return pair;
|
||||
}
|
||||
|
||||
/// Build an LLVM-friendly identifier suffix from a JNI
|
||||
/// `(method_name, signature)` pair. Non-identifier characters are
|
||||
/// rewritten to `_`; the resulting string is unique per pair (the
|
||||
/// caller guarantees uniqueness on `(name, sig)`, which we
|
||||
/// preserve through the separator between mangled name and sig).
|
||||
fn mangleJniKey(self: *LLVMEmitter, name: []const u8, sig: []const u8) []u8 {
|
||||
pub fn mangleJniKey(self: *LLVMEmitter, name: []const u8, sig: []const u8) []u8 {
|
||||
var buf = std.ArrayList(u8).empty;
|
||||
for (name) |b| buf.append(self.alloc, if (isIdentByte(b)) b else '_') catch unreachable;
|
||||
buf.appendSlice(self.alloc, "__") catch unreachable;
|
||||
@@ -1894,7 +1863,7 @@ pub const LLVMEmitter = struct {
|
||||
// back to the per-call `GetObjectClass + GetMethodID`
|
||||
// sequence (1.15 shape).
|
||||
const mid = if (msg.cache_key) |ck| blk: {
|
||||
const pair = self.getOrCreateJniSlots(ck.name_str, ck.sig_str);
|
||||
const pair = self.ffiCtors().getOrCreateJniSlots(ck.name_str, ck.sig_str);
|
||||
const cached_mid = c.LLVMBuildLoad2(self.builder, self.cached_ptr, pair.mid_slot, "jni.cached.mid");
|
||||
const is_cached = c.LLVMBuildICmp(self.builder, c.LLVMIntNE, cached_mid, c.LLVMConstNull(self.cached_ptr), "jni.is.cached");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user