ffi M1.2 A.5: synthesized +alloc IMP + ensureCRuntimeDecl helper
For every sx-defined #objc_class, emit a C-callconv +alloc IMP
that the Obj-C runtime calls when '[Cls alloc]' fires (from sx
code, UIKit instantiation, Info.plist principal class, etc.):
+alloc IMP (cls: Class, _cmd: SEL) -> id
instance = class_createInstance(cls, 0)
state = malloc(STATE_SIZE)
memset(state, 0, STATE_SIZE)
object_setIvar(instance, load(@__<Cls>_state_ivar), state)
return instance
STATE_SIZE = max(typeSizeBytes(state struct), 1) — always at
least one byte so the ivar is never null after +alloc returns.
The IMP is registered on the METACLASS (class methods live there
— every Class object's isa points to the metaclass) in emit_llvm's
class-pair init constructor:
metaclass = object_getClass(cls)
sel_alloc = sel_registerName("alloc")
class_addMethod(metaclass, sel_alloc, alloc_imp, "@@:")
That override wins over NSObject's default +alloc; runtime
instantiations get the __sx_state ivar bound automatically.
Per-instance allocator binding (the plan's full design — store
the Allocator value in the state struct so -dealloc frees through
the same one) is deferred. libc malloc/free is fine for v1; we'll
upgrade once Month 4's autoreleasepool + ARC ops shake out.
REFACTOR: collapsed five duplicate 'get<Name>Fid' helpers and
their cache fields (object_getIvar, object_setIvar,
class_createInstance, malloc, memset) into a single
'ensureCRuntimeDecl(name, params, ret) -> FuncId'. The helper
checks for an existing decl by name first (avoids the
'class_createInstance.1' duplicate-symbol crash when stdlib's
'#foreign' decl is already in the module). One helper instead
of one-per-function = ~150 lines deleted.
object_getIvar / object_setIvar added to stdlib std/objc.sx
so user code can use them too (146 exercises object_getIvar
to verify __sx_state was bound to a non-null state pointer
after +alloc).
146-objc-class-alloc-roundtrip.sx end-to-end against macOS:
'[SxFoo alloc]' returns non-null AND object_getIvar(instance,
__sx_state) returns the state ptr. Real Obj-C runtime, no
mocks.
175 example tests pass (+1). zig build test green.
This commit is contained in:
@@ -29,6 +29,8 @@
|
||||
@OBJC_CLASS_NAME_.19 = private unnamed_addr constant [6 x i8] c"SxFoo\00"
|
||||
@OBJC_METH_VAR_NAME_ = private unnamed_addr constant [5 x i8] c"bump\00"
|
||||
@OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [4 x i8] c"v@:\00"
|
||||
@OBJC_METH_VAR_NAME_.20 = private unnamed_addr constant [6 x i8] c"alloc\00"
|
||||
@OBJC_METH_VAR_TYPE_.21 = private unnamed_addr constant [4 x i8] c"@@:\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
|
||||
@@ -786,6 +788,23 @@ entry:
|
||||
ret { ptr, i64 } %call
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define ptr @__SxFoo_alloc_imp(ptr %0, ptr %1) #0 {
|
||||
entry:
|
||||
%call = call ptr @class_createInstance(ptr %0, i64 0)
|
||||
%callN = call ptr @malloc(i64 4)
|
||||
%callN = call ptr @memset(ptr %callN, i32 0, i64 4)
|
||||
%load = load ptr, ptr @__SxFoo_state_ivar, align 8
|
||||
call void @object_setIvar(ptr %call, ptr %load, ptr %callN)
|
||||
ret ptr %call
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare ptr @class_createInstance(ptr, i64) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @object_setIvar(ptr, ptr, ptr) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @__SxFoo_bump_imp(ptr %0, ptr %1) #0 {
|
||||
entry:
|
||||
@@ -822,7 +841,12 @@ entry:
|
||||
%sel = call ptr @sel_registerName(ptr @OBJC_METH_VAR_NAME_)
|
||||
%1 = call i8 @class_addMethod(ptr %cls, ptr %sel, ptr @__SxFoo_bump_imp, ptr @OBJC_METH_VAR_TYPE_)
|
||||
call void @objc_registerClassPair(ptr %cls)
|
||||
%metacls = call ptr @object_getClass(ptr %cls)
|
||||
%sel_alloc = call ptr @sel_registerName(ptr @OBJC_METH_VAR_NAME_.20)
|
||||
%2 = call i8 @class_addMethod(ptr %metacls, ptr %sel_alloc, ptr @__SxFoo_alloc_imp, ptr @OBJC_METH_VAR_TYPE_.21)
|
||||
%iv = call ptr @class_getInstanceVariable(ptr %cls, ptr @OBJC_IVAR_NAME_)
|
||||
store ptr %iv, ptr @__SxFoo_state_ivar, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
declare ptr @object_getClass(ptr)
|
||||
|
||||
1
tests/expected/146-objc-class-alloc-roundtrip.exit
Normal file
1
tests/expected/146-objc-class-alloc-roundtrip.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
tests/expected/146-objc-class-alloc-roundtrip.txt
Normal file
1
tests/expected/146-objc-class-alloc-roundtrip.txt
Normal file
@@ -0,0 +1 @@
|
||||
alloc: ok, state bound
|
||||
Reference in New Issue
Block a user