ffi M1.2 A.0: objc_defined_class_cache + scan-pass registration
Adds an insertion-ordered cache on Module for sx-defined Obj-C
classes — every '#objc_class("Cls") { ... }' declaration WITHOUT
'#foreign'. registerForeignClassDecl appends the entry alongside
its existing foreign_class_map insert; lookup helper available
via Module.lookupObjcDefinedClass.
ObjcDefinedClassEntry { name, *const ast.ForeignClassDecl }
The pointer back into the AST lets later passes (M1.2 A.1+) walk
'members' for fields / methods / '#extends' / '#implements'
without duplicating that data on the entry. Insertion order
matters because class-pair init constructors (A.4) must register
parent classes before children — 'objc_allocateClassPair(super,
...)' resolves super by lookup.
Infrastructure only — no observable behavior change. The cache
is populated but not yet read; A.1+ start pulling from it. 170
example tests + zig build test green.
This commit is contained in:
@@ -9413,8 +9413,17 @@ pub const Lowering = struct {
|
||||
/// type (e.g. `*Activity`) is resolved via the existing struct
|
||||
/// fallback in `type_bridge.resolveTypeName` (which interns unknown
|
||||
/// named types as 0-field structs).
|
||||
///
|
||||
/// sx-defined Obj-C classes (no `#foreign`, runtime == .objc_class)
|
||||
/// also land in `module.objc_defined_class_cache` in declaration
|
||||
/// order — that cache drives M1.2 class-synthesis emission (A.4+).
|
||||
fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.ForeignClassDecl) void {
|
||||
self.foreign_class_map.put(fcd.name, fcd) catch {};
|
||||
if (!fcd.is_foreign and fcd.runtime == .objc_class) {
|
||||
if (self.module.lookupObjcDefinedClass(fcd.name) == null) {
|
||||
self.module.appendObjcDefinedClass(fcd.name, fcd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazily declare the `sx_jni_env_tl_get` / `sx_jni_env_tl_set`
|
||||
|
||||
@@ -2,6 +2,7 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const types = @import("types.zig");
|
||||
const inst = @import("inst.zig");
|
||||
const ast = @import("../ast.zig");
|
||||
|
||||
const TypeId = types.TypeId;
|
||||
const TypeInfo = types.TypeInfo;
|
||||
@@ -41,6 +42,15 @@ pub const Module = struct {
|
||||
/// `Cls.static_method(...)` against an `#objc_class` alias resolves
|
||||
/// the class object through this cache once per module.
|
||||
objc_class_cache: std.ArrayList(ObjcClassEntry),
|
||||
/// sx-defined Obj-C classes — every `Cls :: #objc_class("Cls") { ... }`
|
||||
/// declaration WITHOUT `#foreign`. Insertion-ordered so the
|
||||
/// class-registration constructors (M1.2 A.4) emit in source order
|
||||
/// — parent classes register before children, which matters because
|
||||
/// `objc_allocateClassPair(super, ...)` resolves `super` by lookup.
|
||||
/// Each entry holds a pointer back into the AST so later passes
|
||||
/// (trampoline emission, +alloc/-dealloc synthesis) can re-walk
|
||||
/// `members` for fields / methods / `#extends` / `#implements`.
|
||||
objc_defined_class_cache: std.ArrayList(ObjcDefinedClassEntry),
|
||||
alloc: Allocator,
|
||||
/// True when this module's program imports `std.sx` (and therefore
|
||||
/// has the `Context` type). Set by lowering's Pass 0 pre-scan. Read
|
||||
@@ -50,6 +60,10 @@ pub const Module = struct {
|
||||
|
||||
pub const ObjcSelectorEntry = struct { sel: []const u8, slot: GlobalId };
|
||||
pub const ObjcClassEntry = struct { name: []const u8, slot: GlobalId };
|
||||
/// Pointer back to the AST node lets later passes re-walk `members`
|
||||
/// for fields / methods / `#extends` / `#implements` without
|
||||
/// duplicating that data here.
|
||||
pub const ObjcDefinedClassEntry = struct { name: []const u8, decl: *const ast.ForeignClassDecl };
|
||||
|
||||
pub fn init(alloc: Allocator) Module {
|
||||
return .{
|
||||
@@ -59,6 +73,7 @@ pub const Module = struct {
|
||||
.impl_table = ImplTable.init(alloc),
|
||||
.objc_selector_cache = std.ArrayList(ObjcSelectorEntry).empty,
|
||||
.objc_class_cache = std.ArrayList(ObjcClassEntry).empty,
|
||||
.objc_defined_class_cache = std.ArrayList(ObjcDefinedClassEntry).empty,
|
||||
.alloc = alloc,
|
||||
};
|
||||
}
|
||||
@@ -72,6 +87,7 @@ pub const Module = struct {
|
||||
self.impl_table.deinit();
|
||||
self.objc_selector_cache.deinit(self.alloc);
|
||||
self.objc_class_cache.deinit(self.alloc);
|
||||
self.objc_defined_class_cache.deinit(self.alloc);
|
||||
self.types.deinit();
|
||||
}
|
||||
|
||||
@@ -101,6 +117,18 @@ pub const Module = struct {
|
||||
self.objc_class_cache.append(self.alloc, .{ .name = name, .slot = slot }) catch unreachable;
|
||||
}
|
||||
|
||||
/// Linear scan over sx-defined Obj-C classes.
|
||||
pub fn lookupObjcDefinedClass(self: *const Module, name: []const u8) ?*const ast.ForeignClassDecl {
|
||||
for (self.objc_defined_class_cache.items) |entry| {
|
||||
if (std.mem.eql(u8, entry.name, name)) return entry.decl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn appendObjcDefinedClass(self: *Module, name: []const u8, decl: *const ast.ForeignClassDecl) void {
|
||||
self.objc_defined_class_cache.append(self.alloc, .{ .name = name, .decl = decl }) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addFunction(self: *Module, func: Function) FuncId {
|
||||
const id = FuncId.fromIndex(@intCast(self.functions.items.len));
|
||||
self.functions.append(self.alloc, func) catch unreachable;
|
||||
|
||||
Reference in New Issue
Block a user