diff --git a/changelog.d/9900-dead-string-wrapper-diag.md b/changelog.d/9900-dead-string-wrapper-diag.md new file mode 100644 index 0000000000..a26f98abdd --- /dev/null +++ b/changelog.d/9900-dead-string-wrapper-diag.md @@ -0,0 +1,4 @@ +### Fixed + +- GC primitive-dispatch diagnostics no longer expose a string-wrapper counter + that lost its only writer when boxed string indices became virtual. diff --git a/crates/perry-runtime/src/gc/diag_sites.rs b/crates/perry-runtime/src/gc/diag_sites.rs index 462d55afcb..5d7776bfab 100644 --- a/crates/perry-runtime/src/gc/diag_sites.rs +++ b/crates/perry-runtime/src/gc/diag_sites.rs @@ -369,22 +369,18 @@ pub(super) fn report_charges(label: &str) { // whose method the native dispatch tower does not recognise falls through to // `native_call_method::call_primitive_builtin_prototype_method`: it resolves // `globalThis..prototype[]` and, for a SLOPPY callee, boxes -// the receiver with `ToObject`. For a string that wrapper materialises one own -// property per UTF-16 code unit. So a single unrecognised method name on a hot -// render path turns into O(length) allocations per call, and the only way to -// tell WHICH names those are is to count them at the fork. +// the receiver with `ToObject`. A string wrapper exposes one virtual own index +// per UTF-16 code unit, so tracking receiver length shows the scale of the +// boxed surface alongside the method names that reach this fork. crate::perry_thread_local! { /// `".prototype." -> (calls, receiver_utf16_chars)`. static PRIMITIVE_DISPATCH: RefCell> = RefCell::new(HashMap::new()); - /// String wrappers actually materialised: (wrappers, index properties). - static STRING_WRAPPERS: Cell<(u64, u64)> = const { Cell::new((0, 0)) }; } /// Record one trip through the primitive-method fallback. `recv_chars` is the -/// receiver's UTF-16 length (0 when the receiver is not a string) — the number -/// of own index properties a sloppy callee's `ToObject` wrapper costs. +/// receiver's UTF-16 length (0 when the receiver is not a string). pub(crate) fn primitive_dispatch(builtin: &[u8], method: &str, recv_chars: u64) { if !gc_diag_enabled() { return; @@ -403,12 +399,6 @@ pub(super) fn report_primitive_dispatch(label: &str) { if !gc_diag_enabled() { return; } - let (wrappers, indices) = STRING_WRAPPERS.with(Cell::get); - if wrappers > 0 { - eprintln!( - "[gc-primitive-dispatch] {label}: string_wrappers={wrappers} index_properties={indices}" - ); - } let rows: Vec<(String, (u64, u64))> = PRIMITIVE_DISPATCH.with(|m| m.borrow().iter().map(|(k, v)| (k.clone(), *v)).collect()); if rows.is_empty() { diff --git a/scripts/gc_runtime_root_holders.json b/scripts/gc_runtime_root_holders.json index 1bbbb6b148..e097e960ad 100644 --- a/scripts/gc_runtime_root_holders.json +++ b/scripts/gc_runtime_root_holders.json @@ -341,12 +341,6 @@ "verdict": "not_a_gc_pointer", "why": "#9794: per-method primitive-dispatch counts, `HashMap`. Rust-owned method-name strings and counters." }, - { - "file": "crates/perry-runtime/src/gc/diag_sites.rs", - "name": "STRING_WRAPPERS", - "verdict": "not_a_gc_pointer", - "why": "#9794: materialized/elided string-wrapper counts as a `(u64, u64)` pair." - }, { "file": "crates/perry-runtime/src/gc/oldgen_defrag.rs", "name": "LAST_IDLE_PREDICTED_RELEASE",