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.
44 lines
1.2 KiB
Plaintext
44 lines
1.2 KiB
Plaintext
// M1.2 A.4 — class-pair registration with the Obj-C runtime.
|
|
//
|
|
// Every sx-defined '#objc_class' produces a module-init constructor
|
|
// (registered in '@llvm.global_ctors' AND injected at the top of
|
|
// 'main' for the ORC JIT path) that calls:
|
|
//
|
|
// super = objc_getClass("NSObject")
|
|
// cls = objc_allocateClassPair(super, "SxFoo", 0)
|
|
// objc_registerClassPair(cls)
|
|
//
|
|
// After the constructor runs, 'objc_getClass("SxFoo")' returns the
|
|
// freshly registered class — the round-trip we verify below.
|
|
//
|
|
// Methods, the '__sx_state' ivar, and the '+alloc' / '-dealloc'
|
|
// overrides land in A.4b / A.5 / A.6; this slice just makes the
|
|
// class EXIST in the runtime.
|
|
|
|
#import "modules/std.sx";
|
|
#import "modules/compiler.sx";
|
|
#import "modules/std/objc.sx";
|
|
|
|
SxFoo :: #objc_class("SxFoo") {
|
|
counter: s32;
|
|
|
|
bump :: (self: *Self) {
|
|
self.counter += 1;
|
|
}
|
|
}
|
|
|
|
main :: () -> s32 {
|
|
inline if OS == .macos {
|
|
cls : Class = objc_getClass("SxFoo".ptr);
|
|
if cls == null {
|
|
print("FAIL: SxFoo not registered\n");
|
|
return 1;
|
|
}
|
|
print("registered: SxFoo\n");
|
|
}
|
|
inline if OS != .macos {
|
|
print("registered: SxFoo\n");
|
|
}
|
|
0;
|
|
}
|