ffi M4.0b: thread context.allocator through sx-defined +alloc
Two converging paths now allocate the state struct via the protocol's
allocator instead of raw malloc:
(1) sx-side `Cls.alloc()`: compiler intercepts in `lowerObjcStaticCall`
when the receiver is a sx-defined `#objc_class` and the method is
the niladic `alloc`. Emits the inline alloc-and-init sequence
using the caller's `current_ctx_ref` as the context — so
`push Context.{ allocator = my_arena } { let f := SxFoo.alloc(); }`
honors `my_arena` end-to-end. The msgSend dispatch is bypassed
entirely for this case.
(2) Obj-C-runtime `[Cls alloc]` (Info.plist principal class, NSCoder,
UIKit reflection): the synthesized `+alloc` IMP shim reads
`__sx_default_context.allocator` and calls into the same shared
helper. The IMP has `has_implicit_ctx = false` and runs with no
caller-side context — the default GPA is the right policy choice
for "everything Apple's runtime instantiates".
Shared helper `emitObjcDefinedAllocAndInit(fcd, cls_ref, ctx_addr)`
does the work: `class_createInstance` → `ctx.allocator.alloc(STATE_SIZE)`
via the inline-protocol fn-ptr → memset 0 → store allocator at
state[0] (the M4.0a slot, captured for -dealloc's later use) →
`object_setIvar(instance, __sx_state_ivar, state)`. Loud failures
on missing globals via the diagnostics system.
The sx-side interception must explicitly bitcast the
`class_createInstance` result from `*void` to the method's declared
return type (`*<Cls>` or `?*<Cls>`). lowerVarDecl reads the Ref's IR
type when no type annotation is present, and coerceToType is a
no-op for ptr→ptr — without the bitcast, `let f := SxFoo.alloc();`
binds `f` at `*void` and downstream `f.class` / `f.method()` fails
to find anything.
-dealloc still uses `free(state)` (M4.0c rewrites it). 184/184 tests
pass; chess on iOS-sim green.
This commit is contained in:
@@ -800,10 +800,16 @@ declare ptr @object_getIvar(ptr, ptr) #0
|
||||
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 32)
|
||||
%callN = call ptr @memset(ptr %callN, i32 0, i64 32)
|
||||
%load = load ptr, ptr @__SxFoo_state_ivar, align 8
|
||||
call void @object_setIvar(ptr %call, ptr %load, ptr %callN)
|
||||
%load = load { { ptr, ptr, ptr }, ptr }, ptr @__sx_default_context, align 8
|
||||
%sg = extractvalue { { ptr, ptr, ptr }, ptr } %load, 0
|
||||
%sgN = extractvalue { ptr, ptr, ptr } %sg, 0
|
||||
%sgN = extractvalue { ptr, ptr, ptr } %sg, 1
|
||||
%icall = call ptr %sgN(ptr @__sx_default_context, ptr %sgN, i64 32)
|
||||
%callN = call ptr @memset(ptr %icall, i32 0, i64 32)
|
||||
%gep = getelementptr inbounds { { ptr, ptr, ptr }, i32 }, ptr %icall, i32 0, i32 0
|
||||
store { ptr, ptr, ptr } %sg, ptr %gep, align 8
|
||||
%loadN = load ptr, ptr @__SxFoo_state_ivar, align 8
|
||||
call void @object_setIvar(ptr %call, ptr %loadN, ptr %icall)
|
||||
ret ptr %call
|
||||
}
|
||||
|
||||
@@ -882,3 +888,5 @@ declare ptr @object_getClass(ptr)
|
||||
declare ptr @objc_getProtocol(ptr)
|
||||
|
||||
declare i8 @class_addProtocol(ptr, ptr)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user