PR #9479 fixed the unrooted dynamic-dispatch receiver (soundness) with a deliberately conservative RootedGroup: the window states collects = true unconditionally over [receiver, ...args].
Measured cost of that conservatism (same-SHA A/B on the cc binary):
.text +1.39%, .perry_gcmap +6.03%
- Microbenchmarks: non-pointer argument 0%, call-result receiver 0%, local receiver + heap-allocating argument +0.6 ns/call (+28% of a loop body that is nothing but the dispatch, resolved to a guarded direct call)
The available narrowing: per-operand truthful windows — root only across the sub-range where a collection can actually occur. That requires js_object_get_own_field_or_undef and js_object_get_class_id to be certified in gc_call_effects (they currently default to may-collect). Certifying them is a broader change than a soundness fix should have carried, which is why #9479 took the conservative path and this is filed separately.
Before building
Compute the ceiling first: +0.6 ns/call on the worst shape, ×(how many such calls a real workload makes). If cc --help/--version instruction counts did not move measurably under #9479, this may be a wontfix — the microbench shape (a loop that is only the dispatch) does not occur in real code at meaningful density. A perf stat -e instructions A/B on cc --help with base vs #9479 binaries answers it in one run; both binaries are kept at /root/claude-roots/ (app_base43, app_roots).
If it is worth building
The certification needs to prove the two helpers cannot reach user code or allocation on any path (getter dispatch happens above them in the tower, not inside). If either can throw, the unwind path counts. The blast radius of a wrong certification is the same silent stale-pointer class #9479 fixed, so the bar is the gc_call_effects audit protocol, not inspection.
PR #9479 fixed the unrooted dynamic-dispatch receiver (soundness) with a deliberately conservative
RootedGroup: the window statescollects = trueunconditionally over[receiver, ...args].Measured cost of that conservatism (same-SHA A/B on the cc binary):
.text+1.39%,.perry_gcmap+6.03%The available narrowing: per-operand truthful windows — root only across the sub-range where a collection can actually occur. That requires
js_object_get_own_field_or_undefandjs_object_get_class_idto be certified ingc_call_effects(they currently default to may-collect). Certifying them is a broader change than a soundness fix should have carried, which is why #9479 took the conservative path and this is filed separately.Before building
Compute the ceiling first: +0.6 ns/call on the worst shape, ×(how many such calls a real workload makes). If cc
--help/--versioninstruction counts did not move measurably under #9479, this may be a wontfix — the microbench shape (a loop that is only the dispatch) does not occur in real code at meaningful density. Aperf stat -e instructionsA/B on cc--helpwith base vs #9479 binaries answers it in one run; both binaries are kept at/root/claude-roots/(app_base43,app_roots).If it is worth building
The certification needs to prove the two helpers cannot reach user code or allocation on any path (getter dispatch happens above them in the tower, not inside). If either can throw, the unwind path counts. The blast radius of a wrong certification is the same silent stale-pointer class #9479 fixed, so the bar is the
gc_call_effectsaudit protocol, not inspection.