ffi M1.2 A.4: emitObjcDefinedClassInit class-pair registration

For every sx-defined '#objc_class', emit a module-init constructor
that registers the class with the Obj-C runtime at module load.
Pattern mirrors the Phase 3.1 emitObjcClassInit companion:
'@llvm.global_ctors' + ORC-JIT main injection.

Constructor body, per cache entry:

  super = objc_getClass("<ParentName>")  // default NSObject
  cls   = objc_allocateClassPair(super, "<ClassName>", 0)
  objc_registerClassPair(cls)

Parent is read from the foreign_class_decl's '.extends' member;
absent ⇒ NSObject (matches M1.2 A.0 spec). Class-name strings
go through new emitPrivateCString helper that mirrors the
selector-init / class-init shape.

Two new small helpers extracted while we were here:
- lazyDeclareCRuntime — declare-once extern wrapper for Obj-C
  runtime APIs.
- appendModuleCtor — append-or-create global_ctors + ORC-JIT
  injection, factored out of emitObjcClassInit.

143-objc-class-registration.sx exercises the round-trip on
macOS: after main starts, objc_getClass("SxFoo".ptr) returns
non-null. Runs against the real Obj-C runtime.

142's IR snapshot updated — the constructor + ctors metadata
are now part of the expected shape.

DEFERRED (A.4b): method-IMP registration (class_addMethod with
a C-ABI trampoline that reads __sx_state ivar and calls the sx
body). DEFERRED (A.5+): synthesized +alloc / -dealloc IMPs and
the '__sx_state' ivar setup.

172 example tests pass (+1 from 143). zig build test green.
This commit is contained in:
agra
2026-05-25 22:14:31 +03:00
parent 659cdc2276
commit b98a22e3f9
5 changed files with 246 additions and 0 deletions

View File

@@ -22,6 +22,9 @@
@str.16 = private unnamed_addr constant [10 x i8] c"compiled\0A\00", align 1
@str.17 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@str.18 = private unnamed_addr constant [10 x i8] c"compiled\0A\00", align 1
@OBJC_CLASS_NAME_ = private unnamed_addr constant [9 x i8] c"NSObject\00"
@OBJC_CLASS_NAME_.19 = private unnamed_addr constant [6 x i8] c"SxFoo\00"
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__sx_objc_defined_class_init, ptr null }]
; Function Attrs: nounwind
declare void @out(ptr) #0
@@ -735,6 +738,7 @@ entry:
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
call void @__sx_objc_defined_class_init()
%alloca = alloca { ptr, i64 }, align 8
%gep = getelementptr inbounds { ptr, i64 }, ptr %alloca, i32 0, i32 0
store ptr null, ptr %gep, align 8
@@ -778,3 +782,17 @@ entry:
}
declare i64 @write(i32, ptr, i64)
declare ptr @objc_getClass(ptr)
declare ptr @objc_allocateClassPair(ptr, ptr, i64)
declare void @objc_registerClassPair(ptr)
define internal void @__sx_objc_defined_class_init() {
entry:
%super_cls = call ptr @objc_getClass(ptr @OBJC_CLASS_NAME_)
%cls = call ptr @objc_allocateClassPair(ptr %super_cls, ptr @OBJC_CLASS_NAME_.19, i64 0)
call void @objc_registerClassPair(ptr %cls)
ret void
}

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@
registered: SxFoo