From c54ca755fa5da8274e49d13f263f2731929b1b5c Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 19 May 2026 12:59:13 +0300 Subject: [PATCH] ffi 1.4: regression test for shared-selector #objc_call sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 101/101 regression tests pass (+ffi-objc-call-03-selector-sharing). Test exercises four call sites — three sharing "init" and one "release" — to pin the multi-site / multi-selector lowering before 1.5 changes how SEL lookups are cached. Runtime behavior: identical before and after 1.5 (all call sites hit nil receivers; libobjc returns 0 for void). The improvement is visible only in the emitted IR — today: $ ./zig-out/bin/sx ir examples/ffi-objc-call-03-selector-sharing.sx \\ | grep -c "call ptr @sel_registerName" 4 After 1.5 (planned): 2 — one `sel_registerName` per unique selector string, materialized into a static `OBJC_SELECTOR_REFERENCES_` global at module init, then loaded at each call site. Matches the shape clang produces for `@selector(...)`. Worth re-running the above grep after 1.5 lands as a manual sanity check. The IR-shape snapshot harness (auto-diff of `sx ir` output) is deferred; for now we verify by eye. --- examples/ffi-objc-call-03-selector-sharing.sx | 41 +++++++++++++++++++ .../ffi-objc-call-03-selector-sharing.exit | 1 + .../ffi-objc-call-03-selector-sharing.txt | 1 + 3 files changed, 43 insertions(+) create mode 100644 examples/ffi-objc-call-03-selector-sharing.sx create mode 100644 tests/expected/ffi-objc-call-03-selector-sharing.exit create mode 100644 tests/expected/ffi-objc-call-03-selector-sharing.txt diff --git a/examples/ffi-objc-call-03-selector-sharing.sx b/examples/ffi-objc-call-03-selector-sharing.sx new file mode 100644 index 0000000..652e4e2 --- /dev/null +++ b/examples/ffi-objc-call-03-selector-sharing.sx @@ -0,0 +1,41 @@ +// Phase 1 step 1.4 (PLAN-FFI.md): multiple `#objc_call` sites +// with the same selector. Today (after 1.3) each site emits its +// own `call @sel_registerName(<"init">)`; the actual SEL handle +// is recomputed per call. +// +// 1.5 lands selector interning: one static `SEL` global per +// unique selector string (named `OBJC_SELECTOR_REFERENCES_init`, +// matching clang's convention) populated once via the runtime +// at module init. Per call site becomes a single load. +// +// Runtime behavior is unchanged before vs. after 1.5; the +// improvement is visible in `sx ir` only. After 1.5 we should +// see exactly one `sel_registerName` call per unique selector +// string in the emitted IR — verify with: +// +// ./zig-out/bin/sx ir examples/ffi-objc-call-03-selector-sharing.sx \ +// | grep -c "call ptr @sel_registerName" + +#import "modules/std.sx"; +#import "modules/compiler.sx"; + +main :: () -> s32 { + inline if OS == .macos { + // Three calls, same selector, same nil receiver. Today these + // emit three `sel_registerName("init")` calls. After 1.5 the + // emit collapses to one (cached SEL global). + #objc_call(void)(null, "init"); + #objc_call(void)(null, "init"); + #objc_call(void)(null, "init"); + + // A different selector — should remain distinct after 1.5 + // (one cached SEL per unique string, not per call site). + #objc_call(void)(null, "release"); + + print("ok\n"); + } + inline if OS != .macos { + print("skipped (not macos)\n"); + } + 0; +} diff --git a/tests/expected/ffi-objc-call-03-selector-sharing.exit b/tests/expected/ffi-objc-call-03-selector-sharing.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/ffi-objc-call-03-selector-sharing.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/ffi-objc-call-03-selector-sharing.txt b/tests/expected/ffi-objc-call-03-selector-sharing.txt new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/tests/expected/ffi-objc-call-03-selector-sharing.txt @@ -0,0 +1 @@ +ok