ffi M4.A: stdlib NSObject + autoreleasepool helper + extends rooting

Declare `NSObject` in std/objc.sx as `#foreign #objc_class("NSObject")`
with the canonical instance + class-method surface every Obj-C class
inherits: `retain`/`release`/`autorelease`/`new`/`alloc`/`init`/
`description`/`hash`/`isEqual_`/`isKindOfClass_`/`respondsToSelector_`/
`class`. Root the foreign-class hierarchy in uikit.sx at NSObject by
adding `#extends NSObject;` to every previously-unrooted declaration
(NSValue, NSNumber, NSDictionary, NSSet, NSNotification, NSBundle,
NSNotificationCenter, NSRunLoop, CADisplayLink, CALayer, EAGLContext,
UIScreen, UIResponder) plus deeper chain fixes (NSMutableDictionary
extends NSDictionary; UIWindow extends UIView; UIViewController
extends UIResponder). After this, M2.3's extends-chain walk finds
`retain`/`release` on any UIKit-typed value:

  view := UIView.alloc().init();
  defer view.release();        // canonical sx idiom — no language magic

Plus `autoreleasepool(body: Closure())` stdlib helper that wraps
`body` in `objc_autoreleasePoolPush` / `defer objc_autoreleasePoolPop`.
Required for Foundation factory returns; closure-call frame is real
cost so hot loops should inline the push/defer-pop pattern manually.

Smoke test `ffi-objc-arc-01-autoreleasepool.sx` exercises both
patterns; refresh of two IR snapshots picks up the new stdlib decls
appearing in test outputs that include `modules/std/objc.sx`.

185/185 example tests pass; chess on iOS-sim green.
This commit is contained in:
agra
2026-05-26 22:38:32 +03:00
parent 92ac51445d
commit 29404afdee
7 changed files with 160 additions and 22 deletions

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,2 @@
retain/release: ok
autoreleasepool: ok

View File

@@ -903,13 +903,13 @@ entry:
i64 30, label %match.arm.44
i64 32, label %match.arm.44
i64 36, label %match.arm.44
i64 38, label %match.arm.44
i64 39, label %match.arm.44
i64 34, label %match.arm.45
i64 35, label %match.arm.45
i64 44, label %match.arm.47
i64 51, label %match.arm.47
i64 45, label %match.arm.47
i64 52, label %match.arm.47
i64 33, label %match.arm.48
i64 43, label %match.arm.48
i64 44, label %match.arm.48
i64 17, label %match.arm.49
i64 20, label %match.arm.49
i64 22, label %match.arm.49
@@ -918,17 +918,17 @@ entry:
i64 27, label %match.arm.49
i64 29, label %match.arm.49
i64 31, label %match.arm.49
i64 39, label %match.arm.49
i64 40, label %match.arm.49
i64 41, label %match.arm.49
i64 42, label %match.arm.49
i64 45, label %match.arm.49
i64 43, label %match.arm.49
i64 46, label %match.arm.49
i64 47, label %match.arm.49
i64 48, label %match.arm.49
i64 49, label %match.arm.49
i64 50, label %match.arm.49
i64 52, label %match.arm.49
i64 51, label %match.arm.49
i64 53, label %match.arm.49
i64 13, label %match.arm.50
]
@@ -987,7 +987,7 @@ match.arm.44: ; preds = %entry, %entry, %ent
i64 30, label %dispatch.case.76
i64 32, label %dispatch.case.77
i64 36, label %dispatch.case.78
i64 38, label %dispatch.case.79
i64 39, label %dispatch.case.79
]
match.arm.45: ; preds = %entry, %entry
@@ -1007,8 +1007,8 @@ match.arm.47: ; preds = %entry, %entry
%loadN = load { i64, i64 }, ptr %alloca, align 8
%allocaN = alloca { ptr, i64 }, align 8
switch i64 %loadN, label %dispatch.default.139 [
i64 44, label %dispatch.case.140
i64 51, label %dispatch.case.141
i64 45, label %dispatch.case.140
i64 52, label %dispatch.case.141
]
match.arm.48: ; preds = %entry, %entry
@@ -1017,7 +1017,7 @@ match.arm.48: ; preds = %entry, %entry
%allocaN = alloca { ptr, i64 }, align 8
switch i64 %loadN, label %dispatch.default.153 [
i64 33, label %dispatch.case.154
i64 43, label %dispatch.case.155
i64 44, label %dispatch.case.155
]
match.arm.49: ; preds = %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry, %entry
@@ -1033,17 +1033,17 @@ match.arm.49: ; preds = %entry, %entry, %ent
i64 27, label %dispatch.case.173
i64 29, label %dispatch.case.174
i64 31, label %dispatch.case.175
i64 39, label %dispatch.case.176
i64 40, label %dispatch.case.177
i64 41, label %dispatch.case.178
i64 42, label %dispatch.case.179
i64 45, label %dispatch.case.180
i64 46, label %dispatch.case.181
i64 47, label %dispatch.case.182
i64 48, label %dispatch.case.183
i64 49, label %dispatch.case.184
i64 50, label %dispatch.case.185
i64 52, label %dispatch.case.186
i64 40, label %dispatch.case.176
i64 41, label %dispatch.case.177
i64 42, label %dispatch.case.178
i64 43, label %dispatch.case.179
i64 46, label %dispatch.case.180
i64 47, label %dispatch.case.181
i64 48, label %dispatch.case.182
i64 49, label %dispatch.case.183
i64 50, label %dispatch.case.184
i64 51, label %dispatch.case.185
i64 53, label %dispatch.case.186
]
match.arm.50: ; preds = %entry
@@ -1833,6 +1833,15 @@ declare ptr @ns_string(ptr, ptr) #0
; Function Attrs: nounwind
declare ptr @c_string(ptr, ptr) #0
; Function Attrs: nounwind
declare ptr @objc_autoreleasePoolPush() #0
; Function Attrs: nounwind
declare void @objc_autoreleasePoolPop(ptr) #0
; Function Attrs: nounwind
declare void @autoreleasepool(ptr, [2 x i64]) #0
; Function Attrs: nounwind
define internal void @triple_imp(ptr sret({ i64, i64, i64 }) %0, ptr %1, ptr %2) #0 {
entry:
@@ -3610,3 +3619,5 @@ entry:
store ptr %sel, ptr @OBJC_SELECTOR_REFERENCES_tripleValue, align 8
ret void
}

View File

@@ -798,6 +798,15 @@ declare ptr @ns_string(ptr, ptr) #0
; Function Attrs: nounwind
declare ptr @c_string(ptr, ptr) #0
; Function Attrs: nounwind
declare ptr @objc_autoreleasePoolPush() #0
; Function Attrs: nounwind
declare void @objc_autoreleasePoolPop(ptr) #0
; Function Attrs: nounwind
declare void @autoreleasepool(ptr, [2 x i64]) #0
; Function Attrs: nounwind
define internal i32 @universal_imp(ptr %0, ptr %1, i32 %2, i32 %3, i32 %4, i32 %5) #0 {
entry:
@@ -944,3 +953,5 @@ entry:
store ptr %selN, ptr @OBJC_SELECTOR_REFERENCES_actualSelectorName, align 8
ret void
}