Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion crates/perry-runtime/src/object/delete_rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,12 +1252,20 @@ unsafe fn squeeze_holes_and_delete(
crate::gc::runtime_write_barrier_external_slot_span(keys as usize, elements as usize, out);
}
super::rebuild_array_layout_from_slots(keys);
set_object_live_slot_count(obj, std::cmp::min(out, alloc_limit) as u32);
// Publish the squeezed shape BEFORE touching the live-slot bound: the
// squeeze changed the keys array's length in place, and
// `set_object_live_slot_count`'s unchanged-bound early return asserts
// parity against the STAMPED descriptor — which still carries the
// pre-squeeze logical_key_count until the publish below runs. At scale
// the floored bound is usually unchanged, so that assert fired mid-
// transition (#9108, reserved_floor at-scale test SIGABRT).
//
// Slots moved: the per-array key index and any stale descriptors for the
// pre-squeeze states are wrong now. Drop the index (rebuilt on demand)
// and publish the squeezed shape at exactly the surviving hole count —
// zero for an ordinary receiver, the structural reserved floor (#9019)
// for an iterator-family one.
crate::object::shapes::shape_drop(keys);
super::shapes::publish_object_shape_holes(obj, floor as u32);
set_object_live_slot_count(obj, std::cmp::min(out, alloc_limit) as u32);
}
12 changes: 10 additions & 2 deletions crates/perry-runtime/src/object/shapes_slot_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,17 @@ pub(crate) unsafe fn publish_object_shape_holes(
if generation == 0 {
super::shape_id_exhausted_abort();
}
// The key count comes from the ARRAY, not the lineage: the O(1) hole
// delete leaves the length untouched (array == lineage), but the squeeze
// shrinks it in place before republishing — carrying the lineage count
// there left a descriptor disagreeing with the authoritative keys edge,
// which the very next parity assert caught (#9108: reserved_floor
// at-scale SIGABRT took the whole suite down behind it).
let keys_ptr = current.keys as usize as *mut super::ArrayHeader;
let logical_key_count = crate::array::keys_array_len_capped_to_capacity(keys_ptr) as u32;
let id = super::publish_shape_result(super::shape_descriptor_ensure_with_holes(
current.keys as usize as *mut super::ArrayHeader,
current.logical_key_count,
keys_ptr,
logical_key_count,
current.live_inline_slot_count,
generation,
current.object_kind,
Expand Down
Loading